EvanCarroll has asked for the wisdom of the Perl Monks concerning the following question:

Alright mason wizards, I need some quick design advice, I'm currently creating lots of components, each component is essentially a web form, and each form does a different job, ie, one form might take a name and remove privileges on that name, another might add them etc. Then I have a page where each of these forms/widgets/components is loaded an admin console if you will. I'm trying to come up with a way I can have each form work autonomously from the console while having them all embedded in it. So to expand, I can submit the user-name in the revoke privilege form, and upon submission the title for that widget will read something like $username's privileges revoked. But, I can't think of a way to submit the data, allow the widget to know what was submitted, and to be modified for embedding in the console.

This is currently the process:
  1. Widget (bleh.mas) submits to the console (index.html).
  2. Widget (bleh.mas) reads from console's (index.html's) submission variables (the ones that presumably it submitted), to get data for processing.

However, one minute problem, the data fields aren't unique. I call all usernames, 'name_user', and I would like to keep that for consistency. So each widget thinks the name_user field is its and changes the title. So the problem now, is having the widget (bleh.mas) know which widget (out of the pool of them) submitted the data, so I can have the title of that widget (and the underling sql) act accordingly.

The current idea I'm having is a hidden input type, however I hate them, I think it is a sign of bad web design. Another idea which would be pristine if I could figure away to get the model to work would be to have the widgets submit the data to themselves, each widget is a file_component, and to have the widget modify its title (among other things) for the invocation and call the console, where its brethren (other widgets) will be displayed unaltered; but, it would have forgone appearance alterations.



Evan Carroll
www.EvanCarroll.com

Replies are listed 'Best First'.
Re: Mason design issue.
by s_m_b (Acolyte) on Oct 10, 2005 at 12:57 UTC
    hidden input fields are not #bad# design. You need some kind of unique ID that the page can use. Short of having the form name made unique, which would do that same job but is in itself a hidden value, I can't see another easy approach.
Re: Mason design issue.
by martell (Hermit) on Oct 10, 2005 at 19:28 UTC

    So let me try understand what is going on.

    1) You have a set of web forms that each do some action

    2) Foreach action you wrote a mason component to handle the submission.

    3) Each form should be capable to do this action in stand alone.

    4) Each form can be combined into a general page with other forms so you can create the admin view. But each form has variables that are the same.

    5) After executing the action, the portion of the admin that submitted the data should display something in the general page.


    You're questions:

    1) How to combine the different forms in a container so that each form calls the appropriate component without the names of the attributes clashing?

    2) Return to the general page the result of your action?


    The solution to problem 1:

    Create a small java script that you include in every page (using a dhandler for example):

    function perform_action(link,form_handled) { var form=document.forms[form_handled]; form.action=link; form.submit(); }

    In each web form, name each form in the form tag:

    <form method="post" name="<% $form_name %>"> ... </form>

    For each button on your page, define now the form and the path to your component for each web form:

    <button type=button onclick="perform_action('<% component_path %>' +,'<% $form_name>%')">submit</button>

    By naming your forms in the web page, you can use a small javascript to select the correct one by name and submit the data. The name clash disappears because each attribute is unique in each form.

    This is also usable when only one form is needed on a page. So you don't have to include ugly 'if-else' structures in your mason code for your web forms to handle the different cases. The javascript is quite light and i didn't had any compatibility problems with it.

    Because each web form has an unique name and his proper link to his component, only the specified component is called. Be aware, the mason component doesn't know yet from where it is called. He can distinguish the call from the single web form from the call of the general page.


    Still to do, problem2: display the result in the admin console instead. Or make the component known from where it is called.

    Solution to this depends on the general architecture of your application. If you have a MVC architecture, the controller can take care of that part. If not, I recommend hidden fields. It isn't that ugly and will solve your problem quickly.


    I hope this shed some light, otherwise, feel free to specify more in detail what your problem is.

      To expand on one each form is itself a file component. I am staunchly against javascript and I could accomplish the same thing essentially because each form is unique with a name=<% $m->current_comp->name %>

      Code speaks a thousand words, let me show you the solution the I came up with to add closure to this problem, btw I did add a hidden form field.

      <%attr> http_title =>'Admin Widget' widget_title =>'Change Password' </%attr> <div class="window"> <div class="title"> <% $title %> </div> <div class="body"> <form method="post" action="<% $m->caller(0)->name %>"> <table style="width:100%"> <tr> <td style="width:50%"> New Password: <input type="password" name="password" size +="30" /> </td> <td> Confirm Password: <input type="password" name="password_c +onfirm" size="30" /> </td> </tr> <tr> <td colspan="2"> <input type="hidden" name="form" value="<% $m->current_com +p->name %>" /> <input type="submit" value="Change my Password" /> </td> </tr> </table> </form> </div> </div> <%init> if ( $form eq $m->current_comp->name ) { if ( defined $password && defined $password_confirm ) { if ( $password eq $password_confirm ) { $dbh->do( qq{UPDATE users SET "password" = ? WHERE "pkid" = ? +}, {}, sha1_base64($password), $S->{'pkid'} ); $title .= " || You have changed your password.", print $S->{pk +id}; } else { $title .= " || Passwords do not match."; } } else { $title .= " || Not enough information."; } } </%init> <%shared> use Digest::SHA1 q/sha1_base64/; my $title = $m->current_comp->attr('widget_title'); </%shared> <%args> $S $password_confirm => $m->caller_args(1)->{'password'} || undef $password => $m->caller_args(1)->{'password_confirm'} || u +ndef $form => $m->caller_args(1)->{'form'} || undef </%args>


      This is just a sample, and I plan on writing a serious mason tutorial on alot of the concepts I employ in the frameworks I have made.

      $S is the session data sent from the autohandler.

      the other caller ($password_confirm, $password, $form) args come from what ever serves as the console.

      <% $m->caller(0)->name %>allows me to dynamically target the component for posting (though this works with limited success)
      Take notice to if ( $form eq $m->current_comp->name ) dynamic again.

      I still need to fix it up but have a deadline of monday so I'll play with it later.


      Evan Carroll
      www.EvanCarroll.com
Re: Mason design issue.
by johnnywang (Priest) on Oct 10, 2005 at 17:32 UTC
    I'm not sure I fully understand your problem, is this the same as having multiple submit buttons in a single form? in which case, I usually include a hidden field, and use javascript to set the field depending on which button is clicked. Of course, you can aslo name all the buttons the same and give them different values.

    If you pass the @ARGS to each mason component, the component can decide whether to handle it or not.

Re: Mason design issue.
by aufflick (Deacon) on Oct 11, 2005 at 03:01 UTC
    If you want to be able to place these components in other pages which may have forms you should come up with some naming scheme to avoid overlapping form names.

    On your actual question, have you thought about using AJAX? You could call an appropriate method and replace the contents of just that component in place. It obvioulsy introduces certain browser requirements, but it will not depend nor interfere with any other form elsewhere on your page (since the page itself never gets submitted).

    PS: I agree with s_m_b that invisible fields are not necessarily bad. Used in the right way they can be quite nutritious and non-toxic.