I have lots of models and show them in tables. When user needs to do something with several models, we need to give him ability to choose rows.
How can I implement it with checkboxes? Of course I don't want to create special field on my models for every table.
This is simple example.
https://ember-twiddle.com/0b8f429f6ad3e0572438
My tries were:
{{input type='checkbox' checked=model.someNotExistedField}}
But in this case input just doesnt work.
And:
<input type="checkbox" {{action marked model}} checked={{in-arr record selectedItems}} />
In second example I've tried to keep selected ids in an array on context. But id doesnt work too.
There are a few steps to solving this problem, which you have not shown in your code examples.
you dont need to worry about binding a checked value on the checkbox.. it can manage its own internal state, and you can take advantage of it when selecting an item... a native <input> should be fine
<input type="checkbox">
You will need an action (preferably a closure action) that handles what to do when a record is selected
onchange={{action (action "valueHasChanged" item) value="target.checked"}}
You will need an array to store the "selected items"
this.selectedItems = [];
I put together a twiddle as one example of how these pieces fit together.
(This answer should be valid with ember version 1.13.0 and up)
I'am guessing your model is an array of rows.
So try adding a chked (boolean) property to the model structure so you now have one for each row and bind it to the respective checkbox.
I finished with such technic:
components/action-based-checkbox.hbs
{{#if checked}}
<input type="checkbox" {{action changed}} checked="checked" />
{{else}}
<input type="checkbox" {{action changed}} />
{{/if}}
In context we have array with selected items, for instance "selectedItems"
In context we have an action, that manages array
//2 and 3 steps example
actions:{
marked(id){
this.selectedItems.push(id);
var uniq = this.selectedItems.uniq();
this.set('selectedItems', uniq);
},
selectedItems:[],
4.next I put the component to my cell
{{inputs/action-based-checkbox changed=(action marked record.id) checked=(in-arr record.id selectedItems)}}
in-arr my "in_array?" helper, ember 2.3
Related
I'm developing a website where you can create, view and like playlists of movies.
In the "playlist page", which has a "/playlistid" route there is a checkbox that I use as a "like button".
Basically I load an array from my server (let's call it "favorites") with the IDs that I take from this.$route.params.id of the single pages, when you click like.
Now, how do I bind the v-model with my local (loaded) array, to check if $route.params.id is included inside, and make the input checked if this last check is true?
This is my code.
HTML side:
<label v-if="like" class="ml-2">
<input type="checkbox" class="heart" #change="checkLike" v-model='favorites.includes(this.$route.params.id)'>
<span></span>
</label>
SCRIPT side:
data () {
return {
favorites: []
}
},
methods: {
checkLike() {
if (this.favorites.includes(this.$route.params.id)) {
this.favorites.splice(this.$route.params.id, 1);
axios.patch(...)
} else if (!this.favorites.includes(this.$route.params.id)) {
this.favorites.push(this.$route.params.id)
axios.patch(...)
}
}
Using contains() or indexOf() inside v-model clearly doesn't work, so how could I do this? Thanks in advance for the help.
I think you're trying to use v-model wrong. v-model is used for two-way binding of your components data to be reactive to events. So, if you want to store the values of all the selected fav movies, you can do it very simply using the v-model.
<input type="checkbox" id="1" value="movie1" v-model="favorites">
<label for="movie1">Best One</label>
<input type="checkbox" id="2" value="movie2" v-model="favorites">
<label for="movie2">Okay movie</label>
data () {
return {
favorites: []
}
},
Now the selection of each of those checkboxes will stay up-to-date with our data's values. So if we check Best One, the value for that movie will go into the array, and if we uncheck it, the value will be popped out of that array. You can add as many as you like, and use the same piece of state from our data. It's pretty magical that view lets us do this. Check out more great examples in the docs here
I have been wandering for two to three hours and I found chunks of relevant questions but my scenario just take a little curve. I have to generate a number of checkboxes which obviously would be generated through ng-repeat. How can I show the preselected values which I am getting from Api. Here is the kind of data I am receiving.
Pre-selected data
$scope.categoriess = [{"id":1,"name":"Garden Cleaning"},{"id":3,"name":"Home Cleaning"}].
and this is the data over which I am using ng-repeat.
ng-repeat data
$scope.categories = [{"id":1,"name":"Garden Cleaning"},{"id":2,"name":"Gutter Cleaning"},{"id":3,"name":"Home Cleaning"},{"id":4,"name":"Pool Cleaning"}
HTML
<div ng-repeat="cats in categories">
<input type="checkbox" ng-model="categoriess.id[cats.id]">
<label>{{cats.name}}</label>
</div>
Now how would i tell ng-repeat to check the preselected data, plus if I want to check few more boxes they should also be checked and I want them to store in $scope.categoriess. I have tried a number of solution either with ng-checked or by make a function call in ng-checked I got no expected results.
Why don't u format your data to have another property, something like
{"id":1,"name":"Garden Cleaning", "checked": true}
Such way, when u iterate through the data, you can check the checkbox
<div ng-repeat="cats in categories">
<input type="checkbox" ng-checked="cats.checked">
<label>{{cats.name}}</label>
</div>
I saw this but i did not know how it works god it saved my life. see this checklist-model. Its so simple , no need to use ng-checked or something dynamic , preselected and gets updated easily
[1]: http://jsfiddle.net/iem_usman/v3k6pwrj/1/
Change your html like this :
<div ng-repeat="cats in categories">
<input type="checkbox" ng-model="categoriess.id[cats.id]" ng-checked="isChecked(cats.id);">
<label>{{cats.name}}</label>
</div>
Add this function in your controller :
$scope.selectedCategoriess = [{"id":1,"name":"Garden Cleaning"},{"id":3,"name":"Home Cleaning"}].
$scope.isChecked = function(id){
for (var i = 0; i < $scope.selectedCategoriess.length; i++) {
if ($scope.selectedCategoriess[i].id == id) {
return true;
}
}
return false;
}
If id is available checked value will be "true".
I was under the impression that trackBy function is used only when trying to optimize the performance of *ngFor, so that if something changes, the DOM doesn't have to be rebuild.
However, recently, I came across a situation when trackBy actually fixed a wrong behavior.
Take this for example: https://plnkr.co/edit/nRgdwoiKAMpsbmWaoMoj?p=preview
Focus on Hobbies section, especially HTML:
<div>
<h2>Hobbies</h2>
<div *ngFor="let h of user.hobbies; trackBy:customTrackBy; let i = index">
#{{i}} - {{h | json}}<br />
<input [(ngModel)]="h.name" name="hobby_name_{{i}}" /> <br /><br />
<select [(ngModel)]="h.type_id" name="type_{{i}}">
<option *ngFor="let t of types" [value]="t.id">{{t.type}}</option>
</select>
<br />
<br />
<button class="btn btn-warn" (click)="remove(i)">Remove</button>
<br /><br />
</div>
</div>
I had to explicitly define this part: trackBy:customTrackBy in the first *ngFor. If trackBy is removed, and the following steps are performed:
remove the first item
add a new item
In this case, the inputs of the first item get replaced with the content of the second item (both fields have the same content), however, the values in the model are correct.
trackBy solves this issue, but why?
I would really appreciate any kind of explanation. If this is not the right place to ask this kind of questions please redirect me to the correct one. Thanks.
update
Here's an example of the wrong behavior: https://plnkr.co/edit/u8YajKfHcPiVqY0WcJt7?p=preview remove the first item (cycling) and add a new item (add button) and see how both values get the same default value (BF will get replaced by "default value" even though the model stays correct).
*ngFor by default tracks items by object identity.
If you have primitive values like an array of strings, and use them in
<div *ngFor="let item of items; let i=index">
<input [(ngModel)]="item" name="item{{i}}">
</div>
and you edit one item, then *ngFor gets in trouble, because the identity of the edited item has changed.
With ngForTrackBy you can tell *ngFor to track the item by index, then above code will work fine when you edit fields.
Another use case is when you want *ngFor to track items by some custom object id property instead of the object identity.
I am using this Angular Module but I can not get the work with nested data.
Here is my PLUNKR my output shows country when using object-property="country but when I try to show only states, it doesn't work.
<div class="mrg-top50">
<label>1. Autocomplete field - options list as array of objects</label>
<multiple-autocomplete ng-model="skills" object-property="country" suggestions-arr="skillsList"></multiple-autocomplete>
<label>Selected Model Value : <br />
</label>
{{skills}}
</div>
I could do it in your fiddle like this:
<multiple-autocomplete ng-model="skills" object-property="labels" suggestions-arr="skillsList[0].states"></multiple-autocomplete>
Though this is really dependent on the [0] index , which means only useful when you have just one element in the given array like in the given example.
I want to display a list of things and let users edit them.
The list is generated using ng-repeat. At first when it was displayed, it should be in the form of pure texts. But when the user pushed the corresponding edit button, it should be changed into an input textfield, with the contents unchanged. When the user submits the form, the data is saved and the input should be changed back to pure texts.
Is this compatible with the Angular way of thinking? If so, how do I realize it? If not, what is the correct way to realize the idea in AngularJS?
Something like this would probably work:
<ul>
<li ng-repeat='item in items'>
<span ng-hide='item.editing'>item.value</span>
<input type='text' ng-show='item.editing' ng-model='item.value' />
<button ng-click='item.editing = !item.editing'>Edit</button>
</li>
</ul>
Then in your submit action set item.editing = false for every item in items
other way or way that i prefer with angular js is to keep a track of current item on scope, this works better if you the fields being edited are in large number
$scope.currentitem;
setting current item equal to the item tha's being edited
<button ng-click='currentitem = item'>Edit</button>
Now you can have an form filled in like
<input type='text' ng-model='currentitem.value' />