I've been able to do this in PHP but it's not translating to Salesforce very well.
I have a form to input an Opportunity. It has an Account, a Contact, and a variable number of fields that will be used to create custom objects (For my purposes an Opportunity is a trip, and the custom objects are legs of that trip). The Salesforce controller needs to create a new Opportunity with the Account and Contact (that's the easy part) but then it needs to create a new custom object (Leg__c) for each leg of the trip.
My form looks like this:
<input type="text" name="Account" />
<input type="text" name="Contact" />
<div id="leg0">
<input type="text" name="dep[0]" />
<input type="text" name="arr[0]" />
</div>
<div id="leg1">
<input type="text" name="dep[1]" />
<input type="text" name="arr[1]" />
</div>
...
I'm not even sure where to begin on this one...
Assuming you know how many legs you need, you can simply create a list of them in your visualforce controller:
public list<Leg__c> liLegs {get; set;};
// upon oppty creation:
liLegs = new list<Leg__c>();
for (integer i = 0; i < iNumLegs; i++)
{
liLegs.add(new Leg__c());
}
Then you can just loop over these in your page like so:
<apex:repeat var="v" value="{!liLegs}">
<apex:inputField value="{!v.Dep__c}"/>
<apex:inputField value="{!v.Arr__c}"/>
</apex:repeat>
The input fields will correspond to the fields in each entry in the list, so then in your Save action or whatever you're using you can just insert the list insert liLegs;.
Hope this is of help and I haven't missed the mark, let me know if so! PS. I've just written this code directly in here so it may not be 100% syntactically correct ;)
Related
I would like to create a validator for abide for a set of checkboxes.
Let's consider a set of 5 checkboxes. The user is asked to check 3 max, and at least 1.
So, here is my work-in-progress code:
<div data-abide-validator='checkboxes' data-abide-validator-values='1,3'>
<input type="checkbox"/>
<input type="checkbox"/>
<input type="checkbox"/>
<input type="checkbox"/>
<input type="checkbox"/>
</div>
<script>
$(document).foundation({
validators: {
checkboxes: function(el, required, parent) {
var countC = el.find(':checked').length;
alert(countC);
}
}
});
</script>
At this point, I just try to count the checked inputs. But it seems I can't even trigger the validator... I think I could manage to code my validation stuff if only I could figure out how to trigger it.
Indeed I didn't find many examples of the custom validator, and the official doc did not help me much.
Your HTML markup is not really "correct" for abide. You should be attaching the data-abide-validator attribute to the inputs, not the parent div. Additionally, you need some better markup so abide's default error display can work (and some better use of foundation's grid system to lay it out). I would point you toward the Abide Validation Page on Zurb's site for some examples of form markup.
I've taken the liberty of restructuring your markup to be something that is more becoming of a foundation layout:
<form action="/echo/html/" method="POST" data-abide>
<div class="row">
<div class="small-12 columns checkbox-group" data-abide-validator-limit="1,3">
<label>Check some boxes</label>
<small class="error">You have checked an invalid number of boxes.</small>
<ul class="small-block-grid-3">
<li>
<label>
<input type="checkbox" data-abide-validator="checkbox_limit" value="1" /> 1
</label>
</li>
<li>
<label>
<input type="checkbox" data-abide-validator="checkbox_limit" value="2" /> 2
</label>
</li>
<li>
<label>
<input type="checkbox" data-abide-validator="checkbox_limit" value="3" /> 3
</label>
</li>
<li>
<label>
<input type="checkbox" data-abide-validator="checkbox_limit" value="4" /> 4
</label>
</li>
<li>
<label>
<input type="checkbox" data-abide-validator="checkbox_limit" value="5" /> 5
</label>
</li>
</ul>
</div>
</div>
<div class="row">
<div class="small-12 columns">
<button type="submit">Submit</button>
</div>
</div>
</form>
As to your JS code. It's not correct either. You need to address the abide -> validators namespace of the options, not just validators. I've rewritten your JS code to not only do that, but give the desired effect you wanted:
$(document).foundation({
abide: {
validators: {
checkbox_limit: function(el, required, parent) {
var group = parent.closest( '.checkbox-group' );
var limit = group.attr('data-abide-validator-limit').split(',');
var countC = group.find(':checked').length;
if( countC >= limit[0] && countC <= limit[1] ) {
group.find('small.error').hide();
//return true so abide can clear any invalid flags on this element
return true;
} else {
group.find('small.error').css({display:'block'});
//return false and let abide do its thing to make sure the form doesn't submit
return false;
}
}
}
}
});
In order to check adjacent elements when doing custom validation, you need to have something to target. The el variable in the validation function will be the DOM element of the input/field that is being validated. The required variable will tell you if the field is flagged as being required or not (boolean). The parent variable will be set to the "parent" of the field. I say "parent" because although the label tag is technically the parent of the input element, abide is smart enough to realize that the label is part of the field's element structure and skip over it to the li element instead.
From there, you need a way to identify a common parent. So I added the checkbox-group class to whatever element I decided to make the "parent" of all the checkboxes in the group. This is not a Foundation or Abide "magic" class, but rather something of my own creation for use in the validation function.
From there, you can easily trace the few lines of the validation function to see the workflow: Find the group container object, parse the limits off the container's data-abide-validator-limits attribute, count the number of checked inputs in the container, check if the number checked is between the limits, display/hide the error message and return true/false so abide knows if the field validated or not.
I've got a working Fiddle of it if you care to check it out yourself ;) Hopefully this was informative for you, and I wish you the best of luck playing with the awesome that is Foundation!
i have a model that has a list of sub items in it , something like this :
class MyObj {
public string Name {get;set;}
public List<mySubObject> Items {get;set;}
}
and
class mySubObject {
public string Name {get;set;}
public int Order {get;set;}
}
Now, when i render the list with a for loop and editorFor, the html i get is somethign like this :
<input type="text" name="Items[0].Name">
<input type="Number" name="Items[0].Order">
<input type="text" name="Items[1].Name">
<input type="number" name="Items[1].Order">
...
<input type="text" name="Items[9].Name">
<input type="number" name="Items[9].Order">
Now imagine remove the first element from the HTML via jQuery because i no longer want it in my list, and then save the list. The data that goes back is without the first [0] element
and all the elements from 1 to 9 go to the server but the model binding fails and it displays (on the server) that the list of items is null
What am i doing wrong ?
Is this a bug of the default model binder ?
What am i doing wrong ?
Leaving holes in the indices.
Is this a bug of the default model binder ?
No, it's by design. You shouldn't leave any holes in the indices.
One possibility is to recalculate the indices when you remove a row but you will have to write a ton of crap javascript for that.
I would recommend you using a different approach. Instead of using sequential indices use Guids. The approach is detailed in the following blog post by Phil Haack: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx (Non-Sequential indices section).
And Steven Sanderson illustrated a nice little helper in this post that would allow you to very easily achieve this: http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
That you could use like this:
#using(Html.BeginCollectionItem("Items"))
{
for (var i = 0; i < Model.Items.Count; i++)
{
#Html.EditorFor(x => x.Name)
#Html.EditorFor(x => x.Order)
}
}
and it will generate the following:
<input type="hidden" name="Items.Index" value="F769E33C-4D07-4586-8D9C-63D386C641FA" />
<input type="text" name="Items[F769E33C-4D07-4586-8D9C-63D386C641FA].Name">
<input type="Number" name="Items[F769E33C-4D07-4586-8D9C-63D386C641FA].Order">
<input type="hidden" name="Items.Index" value="F4A4A9BB-4427-497E-BFD5-3CDE1F46095B" />
<input type="text" name="Items[F4A4A9BB-4427-497E-BFD5-3CDE1F46095B].Name">
<input type="number" name="Items[F4A4A9BB-4427-497E-BFD5-3CDE1F46095B].Order">
...
Now feel free to add/remove rows as much as you like on the client with javascript without fearing that it would break the model binding of your collection.
I have multiple fieldsets containing radiobuttons and an input box on a page. I was given this app to maintain and currently the data is saved by iterating over a Scope.Params parameter, picking out each value, using params.get() and passing them along to a method to save.
What is a good way to execute this? Will I always have to use a Scope.Params parameter? I know one can parameterize the values of the input fields of the form in the action that is called upon submit. How do I do it for a fieldset?
Thanks.
In controllers you can automatically get parameters if you have in your method signature.
Let's say you have a from createUser.html calls a POST method in your template. It is in UserController and createUser.
In form you have:
First name: <input type="text" name="firstname" /><br />
Last name: <input type="text" name="lastname" />
<input type="radio" name="gender" value="male" /> Male<br />
<input type="radio" name="gender" value="female" /> Female
so in you controller if you have a method like this:
pulic statid void createUser(String firstname, String lastname, int gender) {
User user = new User(firstname, lastname, gender);
...
}
So you don't necessarily need to get parameters separately.
EDIT -> In order to save multi-fields for same for you could use arrays like:
in form you could have: <input type="text" name="firstname[]" />
in controller:
pulic statid void createUser(String[] firstname ...) {
for (int i=0; i<firstname.length; i++) {
...
}
...
}
Im using struts2 with freemarker template and i want to iterate over inputs and save them in search criteria.
In my action i have
private SearchCriteria criteria.
with method setCriteria and get criteria
public void setCriteria(SearchCriteria criteria) {
this.criteria= criteria;
}
public SearchCriteria getCriteria() {
return criteria;
}
In the criteria I can set list of objects ProductToSearch, with lets say id and label inside.
In my ftl file im iterating over the list of produtctsToSearch
<input id="test1" type="text" name="criteria.produtctToSearch[0].id" value="123" />
<input id="test2" type="text" name="criteria.produtctToSearch[0].label" value="testLabel" />
<input id="test1" type="text" name="criteria.produtctToSearch[1].id" value="123" />
<input id="test2" type="text" name="criteria.produtctToSearch[1].label" value="testLabel" />
but after looking at my criteria object, list of productsToSearch inside is empty.
Im calling my action via ajax with data: $("#form").serialize();
serialized values are:
criteria.produtctToSearch%5B1%5D.id=123&criteria.produtctToSearch%5B1%5D.label=testLabel&...
Can you tell me what am i missing?
I have a form in which people shall be able to add the same portion of elements with a plus-button, so that something like this is produced:
<div id="person-1" class="person">
<input type="text" name="name-1" id="name-1" />
<input type="text" name="age-1" id="age-1" />
</div>
<!-- as of here, it's JS created -->
<div id="person-2" class="person">
<input type="text" name="name-2" id="name-2" />
<input type="text" name="age-2" id="age-2" />
</div>
<div id="person-3" class="person">
<input type="text" name="name-3" id="name-3" />
<input type="text" name="age-3" id="age-3" />
</div>
I already managed to write jquery-code that allows me to add the same elements once again with a new id (name-1, age-1, name-2, age-2, name-3, age-3, …).
Of course, Zend_Form does not know about name-2 and name-3, so it just drops them when the form contains an error and is displayed again. Neither can I access the value of name-2 with $form->getValue('name-2'). I have to go over raw $this->getRequest()->getPost().
Is there a better method I can use to combine Zend_Form and javascript-based added form elements (of same type like an hardcoded element).
Caveat: In the real problem, it’s select and not input. Found out this could make a difference (with ->setIsArray(true)), but using select would blow up the example code.
What you could do is create a subform container inside your main form and add an X amount of subforms to that container.
For example:
class My_Form extends Zend_Form
{
private $_numPersons = 1;
public function setNumPersons($numPersons)
{
$this->_numPersons = (int) $numPersons;
}
public function init()
{
$container = new Zend_Form_SubForm();
$this->addSubForm($container, 'persons');
for($index = 0; $index < $this->_numPersons; $index++) {
$personForm = new My_PersonForm();
$container->addSubForm($personForm, $index+1);
}
}
}
When rendered, the input fields will have names like persons[1][name]. Note the $index+1, Zend_Form does not allow a form to be named '0'.
Ofcourse, you should only use this method if the amount of person subforms is limited.
Another strategy would be to override the isValid method and use a single My_PersonForm form to validate all the person data.
Sidenote; the above code will only work when you define the numPersons as part of the options set, when creating the form instance. E.g.;
$form = new My_Form(array('numPersons' => 10));