ng-repeat appending data multiple times - javascript

HTML
<div ng-app="templeApp" ng-controller="templeList">
<div ng-repeat="temple in temples track by $index" >
<h2>{{temple.strTempleName}}</h2>
<h4>{{temple.strTempleDescription}}</h4>
<h4>5km from current location</h4>
</div>
</div>
JS
var templeApp = angular.module('templeApp', [])
.controller('templeList',function($scope,$http){
$scope.temples = [{"_id":"new","strTempleName":"Temple 1 Name","strTempleDescription":"Temple 1 description","strContactNumber":"+91899999999","strTempleLocation":"Chennai","iTempleRating":5,"strContactPersonName":"","strTempleCoordinates":""}] ;
$http.get("https://gist.githubusercontent.com/vigneshvdm/d106ea482a792c60dff8/raw/c8f020eb54c4068e40884b8d84c972d92e8e4e08/vicky%20test%20file").success(function(data){
$scope.temples = data[0]; //uncomment this line to see error
console.log(data[0]);
});
});
PROBLEM
When i comment the $scope.temples = data[0]; line, ne-repeat is appending data only once, but when i assign the data to $scope.temples its appending same data multiple time
DEMO LINK

remove track by $index in ng-repeat and change the below like this
in this example i used temple.strTempleName for track by filter make sure it is return unique names.
<div ng-app="templeApp" ng-controller="templeList">
<div ng-repeat="temple in temples track by temple.strTempleName" >
<h2>{{temple.strTempleName}}</h2>
<h4>{{temple.strTempleDescription}}</h4>
<h4>5km from current location</h4>
</div>
</div>

Related

Filter Number in an angular object using limitto

I am using a angularjs filter method on an repeated array of items and trying to filter numbers with a limitTo filter. The result is not getting applied to the repeat in the DOM.
Here is the html
<div ng-controller="demo as d">
<input type="text" ng-model="d.test" ng-change="d.filterthis(d.test)"><br>
<div ng-repeat="item in d.items | limitTo:d.limitto track by $index">
<span ng-show="!item.show">{{item.myno}}</span> -
<span ng-show="!item.show">{{$index}} - {{item.mystr}}</span><br>
</div>
</div>
App.js filter function withing angularjs
this.filterthis = function(filter){
that.items.map(function(filter){
return function(obj){
obj.show=true;
if(obj.myno.toString().indexOf(filter) >-1){
console.log(obj);
obj.show=false;
}
return obj;
}
}(filter));
};
Items is a array like this
this.items = [{
show:false,
myno:10,
mystr:"test1"
}];
http://plnkr.co/edit/bTdlTpSeZuPyGpolXLEG
Having "show" as a key on your items, doesnt remove it from the ng-repeat, and so the limitTo filter will still return the items. Instead you should leverage the filter filter in the repeat like so
<input type="text" ng-model="d.search"><br>
<div ng-repeat="item in d.items | filter:{myno:d.search} | limitTo:d.limitto track by $index">
<span>{{item.myno}}</span> -
<span>{{$index}} - {{item.mystr}}</span><br>
</div>
Note that order is important here, if you limitTo and then filter you are only filtering the limit'ed result. You can change the key upon which you filter by changing {myno:d.search} to a different key, alternatively if you want to search the whole object, simply use d.search.
Updated Plunker

Arrays concatenation in AngularJS and owl-carousel environment

I'm trying to load an carousel with angularjs using owl-carousel. I want my carousel to scroll endless, loading items every time the list is fully scrolled and adding queried elements to the actual list. My issue is:
When I get data from the controller of the next page, I want to merge and contact the received items to be merged the the current array and be rendered at the end of the carousel, here is what I've done:
<data-owl-carousel class="owl-carousel" data-options="{navigation: true, pagination: false, rewindNav : false}">
<div owl-carousel-item="" ng-repeat="item in hmc.ProductData.Products track by $index" class="item">
<a ng-href="/#!//{{Page.Culture+'/product/'+item.id}}">
<div class="telewebion-show-box one-row">
<div class="telewebion-show-box-cover">
<ul>
<li>{{::item.title}}</li>
<li>{{::item.price}}</li>
</ul>
</div>
<img ng-src="{{::item.picture_path}}" width="220" height="148" alt="" class="img-responsive"/>
</div>
</a>
</div>
</data-owl-carousel>
And here is my controller:
hmc.getProducts=function(){
ProductFactory.getProducts(hmc.ProductData.Offset,hmc.ProductData.Limit).then(function(Products){
if(hmc.ProductData.Page==0)
{
hmc.ProductData.Products[0]='';
}
hmc.ProductData.Page++;
var tempArray=[];
tempArray.push(Products);
console.log(tempArray);
hmc.ProductData.Products [0]=hmc.ProductData.Products [0].concat(tempArray[0]);
console.log(hmc.ProductData.Products );
hmc.ProductData.UpdateInProgress=false;
});
}
but it doesn't contact and merge the array and wouldn't work.
With tempArray.push(Products); you push a single array, considered as the whole variable, in a single cell of the array tempArray without obtaining the expected result. You should call:
tempArray = tempArray.concat(Products);
This way you push every element of Products in tempArray. Please note that concat does not modify the calling array directly, this behavior force you to reassign its return value to the original tempArray.
I Just did it like this:
hmc.ProductData.Page++;
var tempArray=[];
var tempArray2=[];
tempArray.push(AjaxProducts);
tempArray2.push(hmc.ProductData.Products);
hmc.ProductData.Products= tempArray2[0].concat(tempArray[0]);
tempArray.length = 0;
tempArray2.length = 0;
Now angular ng-repeat just repeat in a single array structure and ajax appends to the end of that array

How to attach function to second element of ng-repeat

I just started learning angular
and I have a question related to ng-repeater
I have an ng-repeater like:
<div ng-if="!promo.promotion.useHTML"
class="{{promo.promotion.monetateId}}"
ng-repeat="promo in promotions track by promo.promotion.slotId">
<div ng-if="!promo.useHTML">
<img ng-src="{{promo.promotion.imageURL}}"
ng-click="promoOnClick(promo.promotion.promotionURL)"/>
</div>
I want to have a different ng-click function on second element of repeater.
How would I get this?
You can try using $index variable which contains the repeater array offset index. You can use it to build conditional statements in your repeater.
<div ng-if="!promo.promotion.useHTML" class="{{promo.promotion.monetateId}}" ng-repeat="promo in promotions track by promo.promotion.slotId">
<div ng-if="!promo.useHTML && $index !== 2">
<img ng-src="{{promo.promotion.imageURL}}" ng-click="promoOnClick(promo.promotion.promotionURL)"/>
</div>
<div ng-if="!promo.useHTML && $index == 2">
<img ng-src="{{promo.promotion.imageURL}}" ng-click="promoOnClickAnotherFunction(promo.promotion.promotionURL)"/>
</div>
</div>
Or as suggested by comment below
<div ng-if="!promo.promotion.useHTML" class="{{promo.promotion.monetateId}}" ng-repeat="promo in promotions track by promo.promotion.slotId">
<div ng-if="!promo.useHTML>
<img ng-src="{{promo.promotion.imageURL}}" ng-click="($index==1) ? function1() : function2()"/>
</div>
</div>
or as a third option, you can pass the index into the callback function as a second parameter and move your logic into your controller.
and in your callback, check the index and ... based on the index call your
function1, or function 2. Its a good idea to move logic away from your templates/views.
even better option would be creating/setting your promote() function function in your controller. E.g when you load your promotions array/objects, loop over them and set their promote function based on ... whatever your requirements are.
var i;
var yourPromoteFunctionForSecondElement = function( promo_object ) {
/*do your promo specific stuff here*/
}
for (i = 0; i < promotions.length; i++) {
var promotion = promotions[i];
if ( i == 1 ) {promotion.promote = yourPromoteFunctionForSecondElement(promotion);}
else if () {promotion.promote = someOtherPromoteFunction(promotion);}
else {/*etc*/}
}

ng-repeat run as many times as integer parameter doesn't work in some cases

I want to run angular as many times as integer value passed to it.
EDIT: I simplified this example because originally I used function to return array based on number passed to it.
HTML
<body ng-app="userFilterModule">
<div class="container-fluid" ng-controller="UserfilterController as Ctrl">
<div class="row">
<div class="filter_tableTbody col-xs-12">
<div class="row filter_tableRow" ng-repeat="user in Ctrl.obj_users">
<!-- ... -->
<div class="col-xs-2">
<span class="filter_rateStars" ng-repeat="a in Ctrl.ratingArr| limitTo: user.rate">
★
</span>
<span class="filter_rateStars notActive" ng-repeat="a in Ctrl.ratingArr| limitTo: 5 - user.rate">
☆
</span>
</div>
</div>
</div>
</div>
</div>
</body>
And everything works fine if ratingArr contains numbers e.g.
app.controller('UserfilterController', function ($scope) {
this.int_male_counter = this.int_female_counter = 5;
this.str_sort_by = {
prop_name: 'f_name',
order: 'asc'
};
//problem starts here
this.ratingArr = [1,2,3,4,5];
this.obj_users = new Users(this.int_male_counter, this.int_female_counter).list;
this.fn_set_sorting = function (str) {
if (this.str_sort_by.prop_name === str) {
this.str_sort_by.order = this.str_sort_by.order === 'des' ? 'asc' : 'des';
} else {
this.str_sort_by.order = 'asc';
this.str_sort_by.prop_name = str;
}
this.obj_users.sortByObjKeyVal(this.str_sort_by.prop_name, this.str_sort_by.order);
};
this.fn_setlected_filter = function (str) {
return str === this.str_sort_by.prop_name;
};
this.fn_is_descending = function(){
return this.str_sort_by.order === 'des';
};
});
But when I change it to new Array(5) or ['','','','',''] or ['a','a','a','a','a']
I get error in console: Error: [ngRepeat:dupes] why?
Thanks!
By default, you cannot use identical values in the array processed by ng-repeat. Quoting the docs:
error:dupes
Duplicate Key in Repeater
Occurs if there are duplicate keys in an ngRepeat expression.
Duplicate keys are banned because AngularJS uses keys to associate DOM
nodes with items.
By default, collections are keyed by reference which is desirable for
most common models but can be problematic for primitive types that are
interned (share references).
As advised in the same docs, just use track by $index suffix (so that items will be keyed by their position in the array instead of their value) to resolve the issue:
<span class="filter_rateStars"
ng-repeat="a in Ctrl.ratingArr | limitTo: user.rate track by $index">

jQuery Concatenate multiple DOM node references into one list

Lets say for example I have the following HTML:
<div class="level0">
<div>level 0 #1</div>
<div class="contents">
<div class="level1">
<div>level 1 #1</div>
<div class="contents">
<div class="level2"><div>level 2 #1</div></div>
</div>
</div>
</div>
</div>
<div class="level0">
<div>level 0 #2</div>
<div class="contents">
<div class="level1"><div>level 1 #2</div></div>
<div class="level1"><div>level 1 #3</div></div>
<div class="level1">
<div>level 1 #4</div>
<div class="contents">
<div class="level2"><div>level 2 #2</div></div>
<div class="level2"><div>level 2 #3</div></div>
</div>
</div>
</div>
</div>
<div class="level0"><div>level 0 #3</div></div>
I want to get all of the references to nodes with class "level0", "level1", or "level2".
Then I want to iterate over them starting with the "level2" references, then going to "level1", then "level0".
For instance, the following code would work for what I am trying to do:
$(".level2").each(function(){
console.log($(this).children().first().text());
});
$(".level1").each(function(){
console.log($(this).children().first().text());
});
$(".level0").each(function(){
console.log($(this).children().first().text());
});
That would make the console output be the following:
level 2 #1
level 2 #2
level 2 #3
level 1 #1
level 1 #2
level 1 #3
level 1 #4
level 0 #1
level 0 #2
level 0 #3
As you can see, they are in order based on class, THEN by order in the HTML from top to bottom. This is what I want
However, I want to store this list of elements in this order so I can just use one loop for all of the elements.
The following code is similar to what I want but displays iterates through the rows in the wrong order.
var $rows = $(".level2, .level1, .level0");
$rows.each(function(){
console.log($(this).children().first().text());
});
This iterates through the rows using in-order traversal.
Is there any way to append these rows into a single variable that I can iterate over in the order I wanted way above?
A rough example using a for loop and _map
var allArr = [],
maxLevel = 2;
for (var i = maxLevel; i > -1; i--) {
var arr = $('.level'+ i ).children('div:first-child').map(function () {
return $.trim($(this).text());
}).get();
allArr = allArr.concat(arr);
}
console.log(allArr);
Needs to be refactored though.
Check Fiddle
I just stumbled upon a working answer looking through a plugins source code.
The solution uses jQuery function $.merge().
The following code accomplishes what I want to do:
var $rows = $(".level2");
var $rows = $.merge($rows,$(".level1"));
var $rows = $.merge($rows,$(".level0"));
$rows.each(function(){
console.log($(this).children().first().text());
});
I supposed if you wanted to get a little more tricky, the following code would also work:
var $allRows = $.merge($.merge($(".level2"),$(".level1")),$(".level0"));
$allRows.each(function(){
console.log($(this).children().first().text());
});
Check out this fiddle to see both options working.

Categories

Resources