Please see this jsfiddle (adapted forked from one by Rich Harris):
http://jsfiddle.net/upgu2tq3/29/
I'm trying to remove an item by index from the 'Posts' keypath. I'm able to do this using the built in splice method. It behaves just like a normal Array.splice. splice(array,startIndex,numberOfItemsToRemove)
{{#each Posts:i}}
<button on-click="splice('Posts',i,1)">Remove {{i}}</button>
{{/each}}
This does the job of removing the item from the keypath. However, upon removal, the value of {{i}} (next to 'Remove') doesn't appear to update.
I've labelled the posts 'Post 0', 'Post 1' etc.. to match up with the index.
It looks like its being iterated by numeric index (from 0 to length-1)? Just the template doesn't seem to update the index when the array is altered. I've checked the length after an item has been removed - its reduced...
I'm just a little confused by this.
It's working as expected.
The index will change after splicing. You can see the button label change after clicking the remove button.
You are getting confused because you have hard-coded the content to "Post 0" etc. The content will not change because the index changed.
If you want it to change then change {{Text}} to Post {{i}}
Related
This question already has an answer here:
Problems with `track by $index` with Angular UI Carousel
(1 answer)
Closed 4 years ago.
I am having an issue with AngularJs ng-repeat and angular-bootstrap-switch
I am using:
ng-repeat="item in items track by $index"
When I added a new item into the first index of array by:
newItem = {};
items.splice(0, 0, newItem);
The DOM contain a bs-switch:
When a new item added it reuse the first element in array base on $index, so it doesn't re-render (that's what I get from this docs). The problem I have is the previous element has switch-on.
The DOM effect issue I have is the class "switch-on" doesn't refresh on new item and it keep on.
Expected: In this case I want to switch is off instead of on like the image. Cause it's an empty object
P/s: Cause of the business so
I cannot add default value for that Switch. It need to be an empty object
I also cannot use any identifier of the item object to track replace to $index
If I use default track by $id it will cause some business issue also
TEMP SOLUTION FOR WHO WORKING ON Angular 1.5 or Upper:
With angular 1.5 and you can use angular-bootstrap-switch 0.5.1
It will fixed the issue, after frapontillo release a changed: "Make "switch-change" trigger when model changes"
Thank you so much for supporting.
What I perceive from your question is that you want to add a new item to main array and when It renders, you want it's switch to be off by default.
Well there are couple of things you need to keep in mind.
ng-repeat only behaves as a loop in our DOM.
If you want to have the switch off by default, you must need to have a model for that in every item of the main array. It'll keep track of every switch's state in DOM.
Here's what you should try
From your controller:
newItem = {switchState: 0};
items.splice(0, 0, newItem);
From your HTML:
<div ng-repeat="item in items track by $index">
<!-- your Name and Decription input fields.. -->
<input
bs-switch
ng-model="item.switchState" />
So I think you're ignoring ng-model of angular-bootstrap-switch which causes you the problem.
If you click this link you can see the code.Problem is when i click on action it is removing redundant data but if i click on another checkbox (i.e family) then it will give the value. but if i put same value as first checkbox (i.e action) then it is showing that value.My aim is if i select two different checkbox it will show only one value
[
{title:'Meet the Robinsons', genre:'action'},
{title:'Meet the Robinsons', genre:'action'},
{title:'MSD', genre:'family'}
]
http://jsfiddle.net/Bw77D/669/
You just need to replace push by splice and remove if (unique):
this.out.splice(0, 1, value);
If I understood right, your problem is when having multiple movies, it only shows the first.
To show all of them you need to remove the condition if (unique) and leave only this.out.push(value);
To show the last item of the list you need to remove the condition if (unique) and replace this.out.push(value); by this.out.splice(0,1,value);
That should fix it.
http://jsfiddle.net/Bw77D/717/
My HTML:
<div class="check" ng-repeat="point in dbs">
<input
name="db"
id="{{point.id}}"
ng-model="point.select"
ng-click="update($index, dbs)"
ng-checked="false"
type="checkbox"
ng-required="point.select" />
</div>
Whilst my update() function looks like:
$scope.update = function(position, dbs) {
angular.forEach(dbs, function(point, index) {
if (position != index)
point.select = false;
});
}
This works as with regards to tracking what the selected checkbox is, and sending into another controller that expects the value, all is working good.
However, when I go back from the resulting page, back to this search form again, somehow the checkbox I selected before, is preselected, and I don't want anything to appear, rather just have everything blank.
Would it be as easy as simply stating:
$scope.point.select = null;
as I can't seem to find a good solution for this, so that the checkbox is always blank / not pre selected when you arrive on this form.
Let me see if I get what you are doing. It looks like you are trying to make your list of checkboxes mutually exclusive. I might look at using a radio button list (a set of radio buttons with the same name attribute, HTML interprets this as a mutually exclusive list). If you create a variable which will hold the value of the selected option and pass that value around, you probably can achieve the same result with less code. Take a look here: https://jsbin.com/sunusihuse/edit?html,js,output
As for clearing the list of controls when you revisit the page, what I have described will do that too because the value of the variable which will hold the selected value is initialized to an empty string. Hope this helps.
I am using AngularJS to create a page which contains a list of products that shows information such as a name, price, region etc. This is displayed kind of like an accordion with the name in the header and extra information in the body.
Since there could be a large amount of these items displayed I am using dirPagination (https://github.com/michaelbromley/angularUtils/tree/master/src/directives/pagination) to paginate these items. My markup at the moment looks like this:
<div class="custom-list" dir-paginate="asset in assets | itemsPerPage: 10 track by $index">
<div class="custom-list-item" ng-class="{'tag-hover': isHoveredTag(asset)}">
<div class="custom-list-item-heading" ng-click="toggleShowAssetDetails(asset)">
<p class="col-lg-5">{{ asset.name }}</p>
<div class="col-lg-offset-2 col-lg-3 rating">
<rating value="asset.rating" />
</div>
<button ng-click="addAsset(asset)"><span class="glyphicon glyphicon-plus"></span></button>
<div class="clearfix"></div>
</div>
<div class="custom-list-item-content" style="display: none" animate="shouldShowAssetDetails(asset)">
...
</div>
</div>
</div>
As you can see I'm using paginate in a pretty standard way just looping through the items in an array and displaying 10 per page. I also have a directive called rating which looks at a value called rating in the item. This is a number from 1 - 5 which is used to display a star rating system next to the name. The directive looks like this:
var rating = function ($compile) {
return {
restrict: "E",
scope: {
value: "="
},
link: function (scope, element, attrs) {
scope.$watch(attrs.rating, function () {
for (var i = 1; i <= 5; i++) {
if (i <= scope.value) {
var starElement = angular.element("<span class=\"icon icon-crown\"></span>");
$compile(starElement)(scope);
element.append(starElement);
} else {
var emptyStarElement = angular.element("<span class=\"icon-empty icon-crown\"></span>");
$compile(emptyStarElement)(scope);
element.append(emptyStarElement);
}
}
})
}
}
}
This looks at the value and inserts the icons based on the value of rating (e.g if the rating was 2 the directive would insert two icon-crown icon spans and 3 icon-empty icon-crown icon spans.
This was working perfectly fine before I included the pagination. However now it will only work for the first 10 items. When you change the page, the rating will not change and just keep the same icons from the previous page, even if the values are different.
I understand this is because the directive sets everything at the beginning and it will not run when you change page because the items aren't reloading they are just being shown and hidden again. But the directive is manipulating the DOM so it doesn't update when the page changes.
The problem is I don't know how to resolve this. I thought about changing the directive to look for the pagination current page instead but then I don't have access to the current list item.
I'd appreciate any help on getting the directive to update the icons when the page is changed.
Update
Here's a link to a Plunker project showing the problem I'm having: http://plnkr.co/edit/VSQ20eWCwVpaCoS7SeQq?p=preview
This is a very stripped down version of the section on my app that I'm having an issue with. There's no styling included although I have kept the CSS class structure. I've also changed the icons to use bootstrap ones just to simplify the Plunker project.
The functionality is the same however. If you go from page 1 to page 2 notice how the stars remain the same despite that fact that the asset rating values are different. However if you go to page 3 and back to page 2 or 1 they will change. The reason this happens is because there are less items on page 3 and therefore when you go back to page 1 or 2 the remaining items will be called again to retrieve the rating values.
You simply need to remove or replace track by $index.
Tracking by $index will give you the following behavior:
There is an array of max 10 length that represents the items to show. The first item will have index 0.
You go to the next page and the items in the array are replaced.
The first item in the array will still have index 0. Since you are tracking by index and the index has not changed, AngularJS will not recreate the DOM node representing the item. Since the DOM node isn't recreated, the directive will not execute this time and the rating will not update.
If you go from page 3 to page 2, the directive will execute for the 7 last elements on page 2, since they didn't exist on page 3, so they are considered new this time.
If you really need to use track by you should use a property that is actually related to the object (and unique), for example:
dir-paginate="asset in assets | itemsPerPage: 10 track by asset.name"
Demo: http://plnkr.co/edit/A80tSEliUkG5idBmGe3B?p=preview
How to refresh the variable assigned in data-ng-init whenever source data changes.
I know how to do that from controller. But is there anyway to do it from html using some directive.
Below is sample demo i have done, were you will see Car and Bike Section
When you click "Add Car" listing and counts get changed as i'm using from the direct source
When you click "Add Bike",
bikeData is not get refreshed, as it holds initial json value only.
data-ng-init="bikeData = (sorted | filter: { type: 'bike' }:true)"
Demo
That's because the bikeData isn't refreshed after. You either need to watch for changes on the your sorted object and update bikeData. Or you can simply slap the same expression you have in your data-ng-init to your ng-click directive. See demo:
http://jsfiddle.net/tomalex0/9jxQK/1/
Another option would be to get rid of the data-ng-init and bind your ng-repeat to the sorted object like you do with cars. For example:
<ul ng-repeat="item in sorted | filter: { type: 'bike' }:true">