Why checkboxes don't work inside a form? - forms

I have an objects array
pets = [{key: 'dog', isChecked: true}, {key: 'hamster', isChecked: false}, {key: 'cat', isChecked: false}];
and display it like checkboxes
<div *ngFor='let pet of pets'>
<input type='checkbox'
name='pets'
value='{{pet}}'
[(ngModel)]='pet.isChecked'
(change)='check()'
/>
{{pet.key}} - {{pet.isChecked}}
</div>
but as soon as I start putting it inside a form
<form>
<div *ngFor='let pet of pets'>
<input type='checkbox'
name='pets'
value='{{pet}}'
[(ngModel)]='pet.isChecked'
(change)='check()'
/>
{{pet.key}} - {{pet.isChecked}}
</div>
</form>
It stops displaying correctly.
How can I make this work with a form?
Plunkr link
and
Plunkr link with a form

HTML :
<form>
<div *ngFor='let pet of pets'>
<input type='checkbox'
name='pets'
id="pets{{getRandom()}}"
[ngModel]="pet.isChecked"
value='{{pet}}'
(click)="$event.stopPropagation(); check();"/>
{{pet.key}} - {{pet.isChecked}}
</div>
</form>
TS :
function getRandom() {
return Math.random() * 1000;
}

Related

Data binding checkboxes in svelte

in a svelte/sapper form I want to send data to a user model
<input type="text" bind:value={user.label}>
..works as expected. But how to send user.offer_ids
let offer_ids = [];
{#each offers as offer}
<label>
<input type=checkbox bind:group={offer_ids} value="{offer.id}">{offer.label}
</label>
{/each}
I can't find any svelte sample how to do this job, which I think is basic in forms.. Thanks for help
May be it was unclear..I want to send data to Json:
<form>
<input type="text" bind:value={user.label}> //gives data to 'user'
{#each offers as offer}
<label>
<input type=checkbox bind:group={offer_ids} value="{offer.id}">{offer.label}
</label>
{/each}
//how to get all selected ids to 'user'
</form>
Hope this is more clear now.
With checkboxes, we bind to checked instead of value:
<script>
let name = 'world';
let flag = false
</script>
<style>
.highlighted {
color: red
}
</style>
<h1 class:highlighted={flag}>Hello {name}!</h1>
<label for="checkbox">Highlight header</label>
<input id="checkbox" type='checkbox' bind:checked={flag}/>
Edit
The offer model should have a selected or checked state. Then you can bind the checkbox to that:
<script>
let name = 'world';
let offers = [
{id: 1, name: 'One', checked: false},
{id: 2, name: 'Two', checked: false},
{id: 3, name: 'Three', checked: false},
]
</script>
{#each offers as offer, index (offer.id)}
<label for={'checkbox'+offer.id}>{offer.name}</label>
<input id={'checkbox'+offer.id} bind:checked={offer.checked} type='checkbox'/>
{/each}
<div>
{offers.filter(offer => offer.checked).map(offer => offer.name)}
</div>
Here, we display three checkboxes and the text below prints the names of the selected offers on the screen.
REPL: https://svelte.dev/repl/461fea432dc54ed0a744afc4e05bf34b?version=3.22.3
so my solution now:
let offer_ids = [];
<form>
{#each offers as offer, i (offer.id)}
<label>
<input type=checkbox bind:group={offer_ids} value="{offer.id}">{offer.label}
</label><br/>
{/each}
</form>
enter code here
and in the function...
async function publish() {
user.offer_ids = offer_ids
const response = await (api.post('users', {user}));

How do I bind a single variable in viewmodel to view

I'm using MVVM in kendo ui. I've seen many examples of using a template to bind lists but I can't find a working example where I bind a single variable to a view item.
I found the following fiddle but its not showing the items in the dropdown. Is there a bug with the code or something else going on?
View:
<div class="form">
<dl>
<dt>Type</dt>
<dd>
<select data-role="dropdownlist" data-bind="source: type, value: expenseType" data-text-field="name" data-value-field="value" ></select>
</dd>
<dt>Merchant</dt>
<dd><input id="merchant" type="text" class='k-textbox' data-bind="value: merchant" /></dd>
<dt>Amount</dt>
<dd><input data-role="numerictextbox" data-bind="value: amount" id="amount" type="text" /></dd>
</dl>
<dt> </dt>
<dd><button id="create" data-bind="click: create" class="k-button">Add</button></dd>
</div>
<div class="span4">
<div data-role="grid" data-sortable="true" data-bind="source: expenses" data-columns='["Type", "Merchant", "Amount"]' ></div>
</div>
ViewModel:
var viewModel = kendo.observable({
// expenses array will hold the grid values
expenses: [],
// type array populates the drop down
type: [{ name: "Food", value: "food"}, { name: "Clothing", value: "clothing"}, { name: "Bills", value: "bills" }],
// expenseType holds the currently selected value of the dropdown list
expenseType: "food",
// the values are bound to the merchant and amount fields
merchant: null,
amount: null,
// event execute on click of add button
create: function(e) {
// add the items to the array of expenses
this.get("expenses").push({Type: this.get("expenseType"), Merchant: this.get("merchant"), Amount: this.get("amount")});
// reset the form
this.set("expenseType", "food");
this.set("merchant", "");
this.set("amount", "");
}
});
// apply the bindings
kendo.bind(document.body.children, viewModel);
https://www.telerik.com/blogs/bind-this-a-look-at-kendo-ui-mvvm
https://jsfiddle.net/burkeholland/NqSuS/6/
The fiddle is broken and the libraries are old. I updated jquery and the CDNs and now the fiddle works:
https://kendo.cdn.telerik.com/2018.2.516/js/kendo.all.min.js
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2018.2.516/styles/kendo.common.min.css" />
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2018.2.516/styles/kendo.blueopal.min.css" />
https://jsfiddle.net/cyufwLea/

Angular 2 - Handling multiple checkboxes checked state

I'm building a registration form, and have to handle multiple checkboxes generated through *ngFor structural directive.
Template:
<div class="form-group">
<label class="col-lg-3 control-label">Response Type</label>
<div class="col-lg-7">
<div class="checkbox" *ngFor="let type of client.responseTypes; let i = index">
<label>
<input type="checkbox" name="responseTypes" [(ngModel)]="client.responseTypes[i].checked" /> {{type.value}}
</label>
</div>
</div>
</div>
TS model object:
client.responseTypes = [
{ value: 'type1', checked: false},
{ value: 'type2', checked: true },
{ value: 'type3', checked: true }
];
The actual values behind the scene checked or unchecked are stored correctly. But, the checkboxes do not show the correct value.
If one of the three objects.checked == false, all checkboxes will show unchecked
Only if all three objects.checked == true, all three will be checked in the form.
I tried fiddling with [value]="client.responseTypes[i].checked" and [checked]="client.responseTypes[i].checked" on the input element, but to no success.
Any pointers in the right direction are massively appreciated.
Regards, Chris
the syntax is ok, well, you can do too
<input type="checkbox" name="responseTypes" [(ngModel)]="type.checked">
the problem is in other place (when you defined the client -I think you write some like this.client.responseTypes=...-), you can write
{{client |json }}
to check it
Alright after trying to wrap my head around why my local application wasn't showing the result I wanted, I started to copy and paste my form-group out of the <form></form> element it was in.
Ta-daa, it works now.
FYI: Placing *ngFor checkboxes inside a <form></form> element results in unwanted behaviour.
In angular every model bind with name , means you need to give unique name to each Form elements`
For Example:
<div class="form-group"><label class="col-lg-3 control-label">Response Type</label>
<div class="col-lg-7">
<div class="checkbox" *ngFor="let type of client.responseTypes; let i = index">
<label>
<input type="checkbox" name="type.id" [(ngModel)]="client.responseTypes[i].checked" /> {{type.value}}
</label>
</div>
</div>
</div>
Object :
client.responseTypes = [{id: '1', value: 'type1', checked: false},
{id: '2', value: 'type2', checked: true },
{id: '3', value: 'type3', checked: true }];
And now Check :) Thank you

Angular2 New Form API: Submitting form without any bindings of its elements

Attention: It should work with the new forms API!
Is there a possibility to submit a raw form without any bindings of its elements?
An Example:
<div class="form-mantle">
<form (ngSubmit)="onSubmitForm1(f1.value)" #f1="ngForm">
<input ngControl="name1" name="name1" type="text" required/><br/>
<input ngControl="text1" name="text1" type="text" required/><br/>
<button class="btn btn-primary" [disabled]="!f1.form.valid">Next </button>
</form>
</div>
<pre>
{{ form1 | json }}
</pre>
How should onSubmitForm1() look like, so that I get form1 like below rendered:
{
name1: "Michael Jackson",
text1: "They don't really care about us"
}
I've already preapared a component to copy+paste, for those, who want to help:
import { Component } from '#angular/core';
#Component({
moduleId: module.id,
selector: 'form1',
templateUrl: 'form1.component.html',
styleUrls: ['form1.component.css']
})
export class Form1Component {
form1 : any = {};
constructor() { }
onSubmitForm1 (data?:any) {
// get raw data from form without bindings
this.form1 = data;
console.log("Data", data);
return false;
}
}
Edit: The exact working copy in plnkr (http://plnkr.co/edit/nMPTYLGxgWzzJuD9Be3f?p=preview) does not work within the seed from https://github.com/mgechev/angular2-seed . Maybe it is a version problem ??
Double binding works without errors:
<div class="form-mantle">
<form (ngSubmit)="onSubmitForm1(f1.value)" #f1="ngForm">
<input [(ngModel)]="f1.name1" #name="ngModel" name="name1" type="text" required/><br/>
<input [(ngModel)]="f1.text1" #name="ngModel" name="text1" type="text" required/><br/>
<button class="btn btn-primary" [disabled]="!f1.form.valid">Next </button>
</form>
</div>
<pre>
{{ f1.value | json }}
</pre>
Just call it like so in your ngSubmit:
(ngSubmit)="onSubmitForm1(f1.value)"
To every control you want to submit add the ngControl attribute to set its name:
<input ngControl="name1" name="name1" type="text" required/><br/>
<input ngControl="text1" name="text1" type="text" required/><br/>
Then in your onSubmitForm1:
onSubmitForm1 (data?:any) {
console.log("Data", data);
this.form1 = data;
}
Plunker for example usage
Yeap, for now (rc4) you have only two ways for accepting a data after submit:
1) model-driven strategy (bindings)
2) template-driven strategy (ngControls)
Finaly the following has worked (double bindings :/ ):
<form (ngSubmit)="onSubmitForm()" #s1="ngForm">
<input [(ngModel)]="step1.name1" [ngModelOptions]="{standalone: true}" type="text" required/><br/>
<input [(ngModel)]="step1.text1" [ngModelOptions]="{standalone: true}" type="text" required/><br/>
<button class="btn btn-primary" [disabled]="!s1.form.valid">Next </button>
</form>

Angular2 log values after dynamically adding form fields

I am trying to console log the values of each object in the choices array. I am currently able to log the objects in the choices array but all of the values are empty. I am seeing timeZonePicker: "", startTimeInput: "", endTimeInput: "" for each object. I am able to add and remove from the choices array and log the key but I cannot log the value. I have tried a lot of different things but still unsuccessful.
<div class="container">
<div class="row">
<div class="col-md-9">
<div *ngFor="let choice of choices; trackBy=customTrackBy" class="form-inline">
<select [ngModel]="choice.timeZonePicker" class="form-control" id="timeZonePicker">
<option *ngFor="let timeZone of timeZones" [selected]="timeZone.chosenTimeZone == '(GMT) Western Europe Time, London, Lisbon, Casablanca, Greenwich'">{{ timeZone.chosenTimeZone }}</option>
</select>
<input [ngModel]="choice.startTimeInput" type="time" class="form-control" id="startTimeInput">
<input [ngModel]="choice.endTimeInput" type="time" class="form-control" id="endTimeInput">
</div> <!-- end form field div -->
<div class="container">
<button (click)="onSubmit()" class="btn btn-primary">Submit</button>
</div>
<div class="container">
<button class="pull-left btn btn-success" (click)="addNewChoice()">Add Field</button>
<button class="pull-left btn btn-danger" (click)="removeChoice()">Remove Field</button>
</div>
</div> <!-- end col-md-9 -->
</div> <!-- end row -->
</div> <!-- end container -->
Below is the component.
export class TimeZonesComponent {
constructor(){}
timeZones = [
{ val: -12, chosenTimeZone: '(GMT -12:00) Eniwetok, Kwajalein'},
{ val: -11, chosenTimeZone: '(GMT -11:00) Midway Island, Samoa'},....];
choices = [
{
timeZonePicker: '',
startTimeInput: '',
endTimeInput: ''
},
{
timeZonePicker: '',
startTimeInput: '',
endTimeInput: ''
}];
addNewChoice(){
var dataObj = {
timeZonePicker: '',
startTimeInput: '',
endTimeInput: ''
};
this.choices.push(dataObj);
}
removeChoice(){
var lastItem = this.choices.length - 1;
this.choices.splice(lastItem);
console.log(this.choices);
}
onSubmit(){
console.log(this.choices);
}
customTrackBy(index: number, obj: any){
return index;
}
}
I really appreciate any help.
I found out my error. I needed to use trackBy (which I wasn't initially) and [(ngModel]). I was only using one way binding but I needed two way. If anyone would like to see the code for learning, just comment and I will happily share it.