get checkbox group values - forms

This has driven me really bananas. It's so simple and easy and yet I can't figure out what's wrong with it.
I want to get my checkbox value populated in my controller (for testing purposes).
Here is my form.
<a href='#' name='submitForm'>submit the form</a>
//I have jquery attached to this tag and will submit the form when user clicks it
echo form_open('test/show');
echo form_checkbox('checkbox[]','value1');
echo form_checkbox('checkbox[]','value2');
echo form_checkbox('checkbox[]','value3');
echo form_checkbox('checkbox[]','value4');
echo "<input type='text' name='text1' value='ddd'>";
echo form_close();
//My controller test
public function show(){
$data1=$this->input->post('text1');
//I can get text1 value from input box
$data2=$this->input->post('checkbox');
//it keeps giving me undefined index 'checkbox'
$data3=$_POST['checkbox'];
//same error message
//WTH is going on here!!!!!
}
Please help. This thing drives me nuts! Thanks.
UPDATE:
Thanks for the help. To be more precisely, my submit button is a <a> tag and outside of form tag. It appear that I have to include <a> tag inside my form tag to make them works. Is that true?

A checkbox will not submit any data if it is unchecked as they're not considered successful (as per the w3c specification here)
If you actually tick the box and submit, it'll work - in fact it does, I've just tested it.
You need to wrap calls to $_POST in the isset() function.
if( isset( $_POST['checkbox'] ) ) {}
Calling $this->input->post('checkbox') shouldn't give you an undefined index error as the method deals with this eventuality. the Input::post() method returns false or the value of the checkbox.
Edit --
In response to your amendment to your question, you must use an element of type input with the type attribute set to submit in order to submit your form data without the use of Javascript etc. This button must be INSIDE the <form></form> which you are intending to submit.
<input type="submit" value="Submit">
The type="submit" causes the browser to send the data as submit event occurs. If you wish to use another element insider or outside of the form to do this you need to use Javascript. This however can be disabled on a per browser/user basis and isn't reliable as a result.
// Standard Javascript
<form name="myform"...
<a onclick="javascript:document.myform.submit();" href="javascript:void(0)">Submit</a>
// jQuery
$('#my-a-tag-submit-button').live( 'click', function() {
$('#my-form').submit();
}

Related

angularjs2: setting fields to "dirty", especially datepicker

I am new to Angular2/Typescript, since I come from the Java world, I decided to learn Typescript and Angular2 directly.
I want to leave most of the logic on the server, thus I don't need complex validation management on the client. So all I want is the user to fill out forms, and post/put all the fields to the REST Service.The goal is to leave the client side as light as possible.
I have a form:
<form role="form" (ngSubmit)="onSubmit()" #ArbeitstagForm="ngForm">
and a field in it, some datepickers too: similar like this:
<input type="text" class="form-control pull-right" id="datepicker" [(ngModel)]="model.datum">
When I submit the form, I call this function:
model = new Arbeitstag();
onSubmit(form:any) {
alert(JSON.stringify(this.model));return false;
}
So that alerts me the the entered data as JSON, which I will after send to a REST Service. It works actually great, BUT only when I actually type something into the field, when I have a default value, or I set the field with a datepicker, the model object values will remain empty.
I've found out about the dirty setting of the fields, which are false by default and are getting true when I type something in and that's also what I see when I check firebug, but that's definitely not what I want to achieve.
Is there a way to set all the fields dirty in a form in Angular2? I've found many examples for Angular.js 1, but not for Angular2/Typescript.
Control has a markAsDirty() (and markAsTouched()) method
<input #datePicker="ngForm" type="text" class="form-control pull-right" id="datepicker" [(ngModel)]="model.datum">
<button (click)="datePicker.control.markAsDirty()">update dirty status</button>
Plunker example
What I usually do is get a reference to the form in my component, using ViewChild. With that reference I can mark to form dirty or touched when I need to. Like so:
export class MyComponent implements OnInit, OnDestroy {
#ViewChild('form') form: NgForm;
...
public methodWithFormChange(): void {
this.form.control.markAsDirty();
}
}
;-)

form with multiple submit buttons that execute different actions

I'm missing something fundamental when it comes to mapping a view to a controller's action and hoping someone can point me in the right direction. I'm working on an existing project and still familiarizing myself with the language and the way it was configured. I have a form that will resolve a qaCase (question answer case) through the resolveForm action and qaCase/resolve view. below is a simplified version of what I have (please let me know if I need to include more information).
QaCaseController
#RequestMapping(value="/resolve/{id}/**", method=RequestMethod.GET)
public String resolveForm(#PathVariable("id") Integer id, Model model) {
QaCase qaCase = qaCaseDAO.findById(id);
// Load the backing objects into the session
model.addAttribute("qaCase", qaCase);
model.addAttribute("users", userDAO.findAll());
model.addAttribute("exams", examDAO.findAll());
return "qacases/resolve";
}
qaCase/resolve.jsp
the resolve view has a form that will accept text input and a resolve button.
<sf:form method="POST" modelAttribute="qaCase" onsubmit="return isValid()">
// some input fields
<input type="submit" name="submitted" value="resolve" />
</sf:form>
when submit button is clicked, the following query string is created
http://localhost:8080/qacases/resolve/<id>/<location>/<name>/<created by>
What I'd like to do is add an additional input field and button to the existing form so I can optionally add comments instead of resolving a case.
<sf:form method="POST" modelAttribute="qaCase" onsubmit="return isValid()">
// some input fields
<input type="submit" name="submitted" value="resolve" />
</sf:form>
<sf:form method="POST" modelAttribute="qaCase" action="addComment">
// optionally Add comment
<input type="submit" name="submitted" value="addComment" />
</sf:form>
If addComment is clicked then I want the query string to be created.
http://localhost:8080/qacases/addComment
Instead, I get the following query string with a 400 status code.
http://localhost:8080/qacases/resolve/<id>/<location>/<name>/<created by>/addComment
I've been going through configuration files to find how the mapping is being set but haven't had any luck. Not sure if this is an answer that can be answered without someone going through the project and determining how it's configured. Appreciate any advice and/or answers.
when you are using action = "addComment" without "/" before "addComment" in <form> that means you are posting your form to current_url_that_invokes_view/addComment
if add "/" to action = "/addComment" you will go to localhost:8080/addComment
so if you need http://localhost:8080/qacases/addComment
type action = "/qacases/addComment" and pay attantion to "/" before qacases to direct root url

AngularJS retrieve from object based on entry in ng-repeat input

This application is for running a writing contest.
Coodinators are assigning entries to judges for them to judge. I have three sets of data I retrieve from the server, a judge list, an entries list and an assignment list that ties the two together. There can be a variable number of input fields...if a judge has agreed to judge 4 entries, there will be 4 inputs...if 7, then 7.
I have all of that working OK, but only insofar as the entry number can be input and the data updated.
Now I would like confirm that the entryID IS a valid ID by checking the list and also to show a field or two on the screen so the coordinator knows that they typed in the right entry.
The relevant section of the HTML
<div ng-app>
<div id="assignment" ng-controller="AssignData" ng-init="JudgeID=107;CategorySelect='MS';PublishSelect='P'">
<div ng-show="loaded">
<form class="entryform ng-cloak" name="assignform" ng-submit="sendForm()">
<p>Entry numbers assigned to this judge</p>
<p ng-repeat="assign in (formassigns =(assigns | filter:AssignedJudge))">
<input type="text" ng-model="assign.entryid" required/>
{{entries.authorname}} {{entries.entrytitle}}
</p>
<button type="submit">Save Assignments</button>
<p>This will keep the assignments attached to this judge.
You will be able to send all of your assignments to all
of your judges when you are finished.</p>
</form>
</div>
</div>
</div>
The part that I haven't been able to figure out is how to make entries.authorname and entries.entrytitle show up when the user types in an entryid that is in entries.entryid.
assigns and entries are both arrays of records using JSON
assigns is JSON made up of assigns.id, assigns.judgeid, assigns.entryid.
entries is JSON made up of entries.entryid, entries.entrytitle, entries.authorname
When assigns arrives, entryid is empty. The form is used to fill in the entryid and when it is filled in, I'd like to be able to show next to it the title and authorname for that entry.
NOTE: I've added some important information at the end of this answer. So please read to the end before you decide what you're going to do.
You're going to have to do something that does the look up.
Also a few other changes I'd add, mostly so you can actually validate the items in your repeat.
(There's a summary of what I did after the psuedo code below).
<div ng-app>
<div id="assignment" ng-controller="AssignData"
ng-init="JudgeID=107;CategorySelect='MS';PublishSelect='P'">
<div ng-show="loaded">
<form class="entryform ng-cloak" name="assignform" ng-submit="sendForm()">
<p>Entry numbers assigned to this judge</p>
<p ng-repeat="assign in (formassigns =(assigns | filter:AssignedJudge))"
ng-form="assignForm">
<input type="text" ng-model="assign.entryid"
ng-change="checkEntryId(assign, assignForm)"
name="entryid" required/>
<span ng-show="assignForm.entryid.$error.required">required</span>
<span ng-show="assignForm.$error.validEntry">
{{assignForm.$error.validEntry[0]}}</span>
{{assign.entry.authorname}} {{assign.entry.entrytitle}}
</p>
<button type="submit">Save Assignments</button>
<p>This will keep the assignments attached to this judge.
You will be able to send all of your assignments to all
of your judges when you are finished.</p>
</form>
</div>
</div>
</div>
Then in your controller, you'd add a function like so (be sure to inject $http or a service you wrote to pull the values from the server):
$scope.checkEntryId = function(assign, form) {
$http.get('/CheckEntry?id=' + assign.entryid,
function(entry) {
if(entry) {
assign.entry = entry;
form.$setValidity('validEntry', true);
} else {
form.$setValidity('validEntry', false, 'No entry found with that id');
}
}, function() {
form.$setValidity('validEntry', true, 'An error occurred during the request');
console.log('an error occurred');
});
};
The basic idea above:
Use ng-form on your repeating elements to allow for validation of those dynamic parts.
Create a function that you can pass your item and your nested form to.
In that function, make your AJAX call to see if the entry is valid.
Check the validity based on the response, and call $setValidity on your nested form you passed to the function.
Use ng-show on a span (or something) in your nested form to show your validation messages.
Also, assign your checked entry to your repeated object for display purposes. (you could use a seperate array if you want, I suppose, but that would probably get unnecessarily complicated).
I hope that helps.
EDIT: Other thoughts
You might want to wrap your call in a $timeout or some sort of throttling function to prevent the entry id check from spamming yoru server. This is an implementation detail that's totally up to you.
If this is a check you do all over the place, you'll probably want to create a directive to do it. The idea would be very similar, but you'll do the check inside of a $parser on the ngModelController.
The method I showed above will still actually update the model's entryid, even if it's invalid. This is usually not a big deal. If it is, you'll want to go with what I suggested in "other thought #2", which is a custom validation directive.
If you need more information about validation via custom directives I did a blog entry on that a while back

CGI Perl - changing action and mode variables

I am somewhat of a novice with CGI Perl and am working on a web app that uses 'mode' and 'action' variables to determine which pages load.
$mode = param('mode');
$action = param('action');
if ($mode eq 'page1') {
if ($action 'eq') {
&performAction;
}
displayPage1;
}
elsif ($mode eq 'page2') {
&displayPage2
}
During development I have been having trouble figuring out the best way to set these variables when trying to navigate to different modes/actions after a form submit.
In some cases, putting a hidden value in the form will work
hidden(-name=>'action',-value=>'save')
but sometimes it will not. In case of the latter, putting param('action',"save") before the form will make the action change when the form is submitted.
I am unable to figure out why this happens though, are there factors that affect these two variables that I am unaware of?
What I now need to do is have two buttons on the same form, one which will just set the action to save the form data, and another which will save the form data but navigate to another mode/page with that form data.
If anyone could at least point me in the right direction for what I should be researching I would be greatly appreciative.
By default the CGI module implements a state-preserving behavior called "sticky" fields. The way this works is that if you are regenerating a form, the methods that generate the form field values will interrogate param() to see if similarly-named parameters are present in the query string. If they find a like-named parameter, they will use it to set their default values.
You want
hidden(-name=>'action', -value=>$new_value, -override=>1)
or
hidden(-name=>'action', -value=>'default_value')
param('hidden_name', $new_value);
This is a try , not sure if it would work.
Try setting hidden variable before button and changing it before every button, so the new value should be taken.
For ex:
<input type='hidden' name='op' value='save'/>
<input type='submit' name='Save Form' value='SaveForm'/>
<input type='hidden' name='op' value='submit'/>
<input type='submit' name='Submit Form' value='SubmitForm'/>
<input type='hidden' name='op' value='cancel'/>
<input type='submit' name='Cancel Form' value='CancelForm'/>
You can check for hidden variable 'op' in perl script.

populated attrib in form element doesn't get its value passed

I'm creating a form text field, but would like to set an additional attribute called additional so the html markup looks like this.
<dd id="email-element">
<input type="text" value="" id="email" name="email" additional="">
</dd>
I'm able to set the attribute using setAttrib like so.
$email = new Zend_Form_Element_Text('email');
$email->setAttrib('additional', '');
$this->addElement($email);
I'm then setting the value of additional on the client side via ajax. But when the form is submitted, additional appears empty. When I var_dump the form, I can see it as an attribute on this form field, but it's empty. Also when I var_dump the request, it's not on it (which is understandable since it's an attribute, and not the field value itself). Is there a way to read attributes that were changed on the client side?
PHP has no way of reading form attributes that were modified in the browser, but you can read it on the client side and send it back to PHP. The only data submitted are the element values themselves.
If you need the attribute in PHP, add a hidden input called additional (or whatever you like), and during the form's onsubmit event, you can read the value of the attribute, and populate the hidden element and then submit the form. Note that if the client has Javascript disabled, the value will not come through, but that method can be used to read it and send it to the server.
Hope that helps.