vuejs model for checkbox group - arrays

I have 2 arrays one for possible checkbox variants and one for already saved-checked boxes.VUEJS template for example
<ul>
<li v-for="cit in possable">
<label>
<input
type="checkbox"
:checked="savedcbx.indexOf(+cit.id)>-1"
:value="cit.id"/>
{{cit.rname}}
</label>
</li>
</ul>
And my question about how add new checkedbox to saved array or delete from saved array uncheckedbox&

You only need one array to achieve toggling. From the Arrays section of Vue.js docs:
HTML:
<div id='example-3'>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
</div>
Vue app:
new Vue({
el: '#example-3',
data: {
checkedNames: []
}
})

I just put savedcbx to model and it works like in answer above.
Vue great thing.
<ul>
<li v-for="cit in possable">
<label>
<input
type="checkbox"
v-model="savedcbx"
//with model this not need too
:checked="savedcbx.indexOf(+cit.id)>-1"
:value="cit.id"/>
{{cit.rname}}
</label>
</li>
</ul>

So, assuming you have this data:
data() {
return {
possable: [1,2,3,4,5],
savedcbx: [3,4]
}
}
If you want to add a new item into savedcbx you just have to push it into the array (make sure it doesn't exist already)
addSavedId (id) {
// Don't add it if it already exists
if(this.savedcbx.indexOf(id) !== -1) return;
this.savedcbx.push(id);
}
To remove an item:
removeSavedId (id) {
let index = this.savedcbx.indexOf(id);
// Nothing to remove if item is not in array
if(index === -1) return;
// Remove `index`
this.savedcbx.splice(index, 1);
}
And now it's up to you when you call the addSavedId(id) and removeSavedId(id) functions and what is the parameter id.

Related

Accessing json object array and showing in Angular 4

I have object that consists of fields, other objects and arrays and it looks like this
Now, in my html, I access data for aaType, adjust etc.
<div class="flexdirectioncolumn">
<div class="flex50">
<label class="label-prop-a"> Name </label>
<div>
<input #name type="text" value={{entity.name}} (keyup.enter)="changeName(name.value)" />
</div>
</div>
<div class="flex50">
<label> AaType </label>
<div>
<input #aaType type="text" value={{entity.aaType}} (keyup.enter)="changeAaType(aaType.value)" />
</div>
</div>
<div class="flex50">
<label> Adjust </label>
<div>
<input #adjustableInput type="checkbox" value={{entity?.adjust}} (keyup.enter)="changeAdjust(adjustInput.value)" />
</div>
</div>
<div class="flex50">
<label> System </label>
<div>
<input #systemInput type="text" value={{entity?.system}} />
</div>
</div>
<div class="flex50">
<label>{{entity.creat.rule}}</label>
<div *ngFor="let param of entity.creat.parameters">
<label>{{param}}</label>
<input type="text" value={{param.value}} />
</div>
</div>
</div>
I managed to show creationInfo.rule that you can see in my html.
Now there is 2 questions that is bothering me:
For some reason, I can't access parameters array so I can use ngFor to create them all.
How can I show my label and input in ngFor div in a way that label will generate parameters name (like "departure-angle") and value in input to show "13"?
Question 1: For some reason, I can't access parameters array so I can use ngFor to create them all.
Answer 1: parameters is not an array it is an object, you cant iterate object using &ngFor
Question 2: How can I show my label and input in ngFor div in a way that label will generate parameters name (like "departure-angle") and value in input to show "13"?
Answer 2:
Solution 1:
In Component add a new variable:
objectArray = Object.keys; // It gives the array of object keys
In html use *ngFor="let param of objectArray(entity.creationInfo.parameters)",
<div class="flex50">
<label>{{entity.creationInfo.rule}}</label>
<div *ngFor="let param of objectArray(entity.creationInfo.parameters)">
<label>{{param}}</label>
<input type="text" value={{entity.creationInfo.parameters[param]}} />
</div>
</div>
Solution 2: You can add a pipe,
This pipe takes the object and return array of objects
import { PipeTransform, Pipe } from '#angular/core';
#Pipe({name: 'array'})
export class ArrayPipe implements PipeTransform {
transform(value, args:string[]) : any {
let array = [];
for (let key in value) {
array.push({key: key, value: value[key]});
}
return array;
}
}
In html,
<div class="flex50">
<label>{{entity.creationInfo.rule}}</label>
<div *ngFor="let param of entity.creationInfo.parameters | array">
<label>{{param.key}}</label>
<input type="text" value={{param.value}} />
</div>
</div>
1.: Parameters is not an array but an Object. So you cannot use *ngFor to access them.
2.: Map the parameters to a key-value array before displaying them.
Inside your ts file:
public params:Array<{key: string, value: string}>;
// Call this method when the "entity" object has been initialized.
private setParams():void {
this.params = Object.keys(this.entity.creationInfo.parameters)
.map(paramKey => ({
key: paramKey,
value: this.entity.creationInfo.parameters[paramKey]
}));
}
And then, inside your template:
<div *ngFor="let param of params">
<label>{{param.key}}</label>
<input type="text" value={{param.value}} />
</div>
Another way to achieve this, is using the Object.entries() function:
public params:Array<Array<any>>;
// Call this method when the "entity" object has been initialized.
private setParams():void {
this.params = Object.entries(this.entity.creationInfo.parameters);
}
Then, inside your template:
<div *ngFor="let param of params">
<label>{{param[0}}</label>
<input type="text" value={{param[1]}} />
</div>

ng-models name collision inside ng-repeat

http://plnkr.co/edit/2UFfaG?p=preview
I used this sample code to build a simple app and I noticed that the edit function doesn't work when you are using ng-models that are repeated in a loop. I know this, because I tried using ng-models outside of the ng-repeat loop and it worked perfectly. So when you have two instances of ng-models with the same name, you get a blank data back when you try to get the values back from the view.
This is my view:
<ul ng-repeat="notes in notes">
<li>
<span ng-hide="editing" ng-click="editing = true">{{note.name}} | {{note.content}}</span>
<form ng-show="editing" ng-submit="editing = false">
<label>Name:</label>
<input type="text" ng-model="name" placeholder="Name" ng-required/>
<label>Content:</label>
<input type="date" ng-model="content" placeholder="Content" ng-required/>
<br/>
<button class="btn" ng-click="edit(note.id)">Save</button>
</form>
</li>
</ul>
This is my edit method:
$scope.edit = function (id) {
var note = notesRef.child(id);
var newNote= {
name : $scope.name,
content : $scope.content
}
};
note.update(newNote);
};
When I refer to a ng-model inside of ng-repeat, I can only get the value null for some reason. I get the correct value when I refer to ng-models outside of the ng-repeat for some reason.
How do we solve this problem? What's the simplest solution?
The problem is that the item belongs to the scope of the repeat.
If you changed your ng-model to:
<ul ng-repeat="notes in notes">
<li>
<span ng-hide="editing" ng-click="editing = true">{{note.name}} | {{note.content}}</span>
<form ng-show="editing" ng-submit="editing = false">
<label>Name:</label>
<input type="text" ng-model="note.name" placeholder="Name" ng-required/>
<label>Content:</label>
<input type="date" ng-model="note.content" placeholder="Content" ng-required/>
<br/>
<button class="btn" ng-click="edit(note)">Save</button>
</form>
</li>
</ul>
Where it's now note.name / note.content.
Then instead of padding the note.id to the edit button, you pass in the entire note i.e ng-click="edit(note)"
Then your controller will get passed the entire note.
$scope.edit = function (note) {
// send note to server via $http, changes to `note` are already made directly to the note itself
};
Hope that makes sense.
it should be like this. As we know ng-repeats directive create their own new scope.
bday.editing
<ul ng-repeat="bday in bdays">
<li>
<span ng-hide="bday.editing" ng-click="bday.editing = true">{{bday.name}} | {{bday.date}}</span>
<form ng-show="bday.editing" ng-submit="bday.editing = false">
<label>Name:</label>
<input type="text" **ng-model="bday.name"** placeholder="Name" ng-required/>
<label>Date:</label>
<input type="date" **ng-model="bday.date"** placeholder="Date" ng-required/>
<br/>
<button class="btn" type="submit">Save</button>
</form>
</li>
</ul>
and here what I understand from your question is that you want to edit only the item on which you have click. this is the solution for the same.
One more solution for the same problem is that create a new function that take one argument that is "bday". make edit true only for this item and set editing false for all others element. this solution is for that case if user doesn't submit the form and click on other item.

Select at least one checkbox validation

I have the array of checkboxes from which I want to select at least one checkbox and want to display the validation error
How can I do that? Here is my code
<div class="form-group" ng-class="{ 'has-error' : submitted && form.field.$invalid }">
<div class="col-md-12"><label for="field" >Select at leat one</label></div>
<div class="col-md-2" data-ng-repeat="i in [1,2,3,4]">
<label><input type="checkbox" name="field[$index]" value="{{i}}" data-ng-model="form.field[$index]" required/>Choice {{i+1}}</label>
</div>
<div ng-show="submitted && form.field.$invalid" class="help-block">
<p ng-show="form.field.$error.required">Please select at least one choice<p>
</div>
</div>
</div>
You can use native javascript functions to iterate over your array. First that come in mind are Array.prototype.some() and Array.prototype.filter().
With some, you can determine if one item in your array validates true and with filter you can find all the elements that pass a custom expression and check if the newly created array has a certain length.
E.g.:
var atleastOne = this.form.field.some(function(element) {
return element;
});
if(atleastOne) {
window.alert("validated with some");
}
var filtered = this.form.field.filter(function(element) {
if(element) { return element; }
});
if(filtered.length > 0) {
window.alert('validated with filter');
}
You can flag the variables that show the errors based on the results of your validation. A working demo can be found here.
You can create your checkbox list object array properly then bind it. Please find the demo
<div ng-controller="ChckbxsCtrl">
<div ng-repeat="chk in items">
<div style="width:500px;height:100px;border:1px solid #000;">
<B>{{chk.group}}</B><br>
<label ng-repeat="vale in chk.values">
<input type="checkbox" ng-model="vale.val" />
{{vale.label}}</label>
</div>
<span ng-show="chk.isValid">Select at least one option from {{chk.group}}</span>
</br> </div>
</br>

Angular show checkbox checked filter

I have a group object that contains a list of video
And when you edit the object, i give the HTML a list of all videos, where you can search in.
But if you don't search I want it to show only the videos that are checked.
here is the HTML used
<div class="input-field">
<input type="text" id="filter" ng-model="query" ng-change="hasVideos()" />
<label for="filter"><i class="mdi-action-search"></i></label>
</div>
<ul class="collection">
<li class="collection-item" ng-repeat="video in filterdVideo = (videos | filter:query) ">
<p>
<input type="checkbox" id="video_{{video.Id}}" checklist-model="group.Keywords" checklist-value="video.Id">
<label for="video_{{video.Id}}">
{{video.Title}}
</label>
</p>
</li>
</ul>
So how can I make it that it only shows the video list where the checkbox is checked? and when the query isn't empty to ignore that and show all.
I will try to improve my answer later.
But for a quick guess you might be able to use ng-if and let the controller handle if something should be listet.
<li ng-if="functionthatreturnstrueorfalsebasedonyourneeds" class="collection-item" ng-repeat="video in filterdVideo = (videos | filter:query) ">
Checkbox example can be found in the docs:
https://docs.angularjs.org/api/ng/directive/ngIf
Fixed it by doing a filter:
filter('filterStack', function () {
return function (inputs, filterValues, showAll) {
var output = [];
if (showAll) return inputs;
angular.forEach(inputs, function (input) {
angular.forEach(filterValues, function (filterVal) {
if (filterVal.Id == input.Id) {
output.push(input);
}
});
});
return output;
};
})
but having an other issue now, when loading it in with data: https://stackoverflow.com/questions/29749006/angular-checklist-model-not-checking

get checked and unchecked of checkbox in angularJS

If we have multiple checkbox in ng-repeat and i want to determine in which checkbox is checked or unchecked in controller's action. so i was not able to do it.
<ul class="list-month" id="divMonths">
<li ng-repeat="m in model.Months">
<div>
<input type="checkbox" id="{{m.Month}}" ng-model="$index" class="left" ng-change="onClickMonth($index)" />
</div>
</li>
</ul>
$scope.onClickMonth = function (id) {
if (id=== true) {
alert("true");
}
else {
alert("false");
}
};>
You could also just use the multiple option.
<select multiple="multiple" ng-model="value" ng-options="m in model.Months"> </select>
value will then be an array that is filled as soon as a checkboxed is selected.

Resources