Remove an object from list of child objects in Model by checkbox unset in Fluid - typo3

I have two Extbase models with 1:n relation. Parent relates to Children via ObjectStorage.
What I want to achieve: editAction($parent) which shows a list of all Children as entries with a checkbox (checked by default). User is allowed to unset any checkbox, submit a form and corresponding Children should be removed from Parent relation.
What I've done so far.
In a fluid I iterate over objects and output the checkboxes like this:
<f:for each="{parent.children}" as="child" iteration="iteration">
<f:form.checkbox property="children.{iteration.index}" value="{child}" />
<label>{child.title}</label>
</f:for>
This generates following HTML, which seems okay for me:
<input type="hidden" name="tx_myext_plugin[parent][children][0][__identity]" value="">
<input type="checkbox" name="tx_myext_plugin[parent][children][0][__identity]" value="135" checked="checked">
<label>child0-title</label>
<input type="hidden" name="tx_myext_plugin[parent][children][1][__identity]" value="">
<input type="checkbox" name="tx_myext_plugin[parent][children][1][__identity]" value="136" checked="checked">
<label>child1-title</label>
...
But when I unset the 2nd checkbox (uid=136) and submit a form, I get the following Exception
#1297759968: Exception while property mapping at property path "children.1": The identity property "" is no UID.
Which also seems logical, because there is that hidden input, that submits an empty value.
I think, I can hook somewhere in MVC-process and just filter out the entries with empty __identity, but is there a more elegant (e.g. best practice) way?
TYPO3 7.6.11

In your controller, you can make an initialize*Action() function. There you can filter out your empty values so that only values with an identity exsist.
public function initializeSaveAction()
{
if ($this->request->hasArgument('parent')) {
$parent = $this->request->getArgument('parent');
foreach ($parent['children'] as $key => $child) {
if (!$child['__identity']) unset($parent['children'][$key]);
}
$this->request->setArgument('parent', $parent);
}
}
Now your saveAction is called after the initializeSaveAction and has only the selected children keept.

Related

How to pass a boolean value in Laravel from a form to the Database?

I tried checkbox it passes on when the checkbox is clicked. Is there no way to pass a boolean value in laravel from a form in laravel ?..
Define an eloquent mutator like this in your model (\App\MyModelName.php):
public function setXXXAttribute($value)
{
$this->attributes['xxx'] = ($value=='on');
}
where "XXX" is the tame of the database column.
The attribute xxx will be set to true in case the value of the checkbox is 'on'
When submitting the Form give the checkbox a value of true. This will then be passed through the form data.
<input type="checkbox" name="checkbox_name" id="checkbox" value="true"/>
I used eloquent mutators in laravel to solve this...
public function setOpenTodayAttribute($value)
{
$this->attributes['open_today'] = ($value=='on')?($value=1):
($value=0);
}
if the value is on i,e checked $value=='on' it will be set to1which is
*boolean* else it will be set to 0 which is false
Add in your form
{!! Form::checkbox('checkbox_name', '1'); !!}
When the checkbox_name is clicked, you can get value from $request->all() array by 'checkbox_name'.
Or
$checked = $request->has('checkbox_name')
Do you mean Model's Attribute Casting?
https://laravel.com/docs/5.5/eloquent-mutators
I needed an actual true or false to be sent, because a validation method wouldn't accept true or nothing. Here is what I did.
<input type="hidden" name="myBoolean" value="0">
<input type="checkbox" name="myBoolean" value="1">
this above returns 0
if you check the checkbox, and the DOM looks like this
<input type="hidden" name="myBoolean" value="0">
<input type="checkbox" name="myBoolean" value="1" checked>
Now the second named element with the same name overwrites the first, and it returns 1.
litteral true/false would work as well
I''l be honest. I don't think this is a best practice approach. It is a quite clean easy to read, simple workaround though.

How to edit an item which is created using a single form on Angular2?

I am new to angular2 & I have a form which can add more item to a page (item with name & decription). This works really well, I can keep on adding new item to my list.
However, each of this item has its own edit & delete. How can I edit and delete each of the item using that only 1 form?
<form #formExperiencesRef="ngForm">
<label for="name">name</label>
<input id="name" type="text" name="fruit [(ngModel)]="formData.name">
<label for="description">description</label>
<input id="description" type="text" name="fruit [(ngModel)]="formData.description">
<button (click)="onSubmit(formExperiencesRef.value)"></button>
</form>
This single form is what I use to keep on adding new item. And now I find it hard to edit the item that I created using this. Can someone help me?
Often I would advise to go with a reactive form for all it's benefits, but if your form is this simple a template driven approach can be sufficient.
First of all I see problem in your form. Your name attributes are the same for both fields, this will mean that they are evaluated as one and the same. I would actually name them as for how your formData object looks like, and then just push the form value as is to the array. I'll just use one way binding here for the sake of the editing of item. Also pass the form object in submit.
How we can edit can be done numerous ways. Here we'll utilize the index of your list (assumingly it's an array).
<form #formExperiencesRef="ngForm" (ngSubmit)="onSubmit(formExperiencesRef.value)">
<input name="name" [ngModel]="formData.name">
<input name="description" [ngModel]="formData.description">
<button type="submit">Submit</button>
</form>
Your list:
<div *ngFor="let item of items; let i = index">
{{item.name}} <button (click)="edit(item, i)">Edit</button>
</div>
And in the TS, we can use #ViewChild to reference our form, which I am using to reset the form:
#ViewChild('formExperiencesRef') formExperiencesRef: NgForm;
and your methods for editing and saving a new item:
formData = {};
items = [];
index = null; // used to store current index value of item (if exists)
edit(item, i) {
this.index = i;
this.formData = item;
}
onSubmit(val) {
// check if index exists, if not it's a new item
if(this.index == null) {
this.items.push(val)
} else {
this.items[this.index] = val;
}
// reset index & form
this.index = null;
this.formExperiencesRef.reset();
}
DEMO: http://plnkr.co/edit/ksHp10WwaDg4AQjwDf2d?p=preview
For the future, I really suggest you check out reactive forms, you have tighter control over your form, handle validations easier and a big,big advantage to me is especially if you are dealing with nested components. Reactive forms can be confusing in the beginning, but it's worth it! :)

Spray - Parsing forms with checkboxes

I am setting up a simple API part of which accepts POST requests via form submission. The form requires the user to select one or more checkboxes all sharing the same name e.g.
<form>
<input type='text' name='textval'>
<input type='checkbox' name='cbox' value='val1'> Value 1
<input type='checkbox' name='cbox' value='val2'> Value 2
<button type='submit'>Submit</button>
</form>
I am attempting to handle the request in Spray like so:
path("mypath") {
post {
formFields('textval, 'cbox) { (textval, cbox) =>
// Now what?
}
}
}
I cannot find documentation in the Spray Docs on how to handle such inputs. In fact, this seemed to be an issue that has now been fixed, but I am unsure how to handle this form field with the Spray API
I have found a somewhat hacky solution to meet my needs. I have changed the names of my checkboxes to represent the values associated with them, and I use optional form fields in my spray route
Here is my new form
<form>
<input type='text' name='textval'>
<input type='checkbox' name='cbox1' value='val1'> Value 1
<input type='checkbox' name='cbox2' value='val2'> Value 2
<button type='submit'>Submit</button>
</form>
The route changes accordingly
path("mypath") {
post {
formFields('textval, 'cbox1.?, 'cbox2.?) { (textval, cbox1, cbox2) =>
complete(s"textval:'$textval', cbox1:'$cbox1', cbox2:'$cbox2'")
}
}
}
The optional fields get mapped to type Option[String] which can then be easily checked with .isEmpty or something similar to determine whether the checkbox was checked.
However, one issue is that it will allow forms to be posted with no checkboxes selected since they are all optional. You could perhaps set one as default.

Submitting list of items with removed first one deletes all items

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.

Dynamically adding form elements with jQuery and Zend_Form

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));