How to iterate through array as item is added in Angularjs? - javascript

I used ng-repeat to loop through array made in controller. The problem is, instead of showing each value in a new row, it shows all of the array values in every row, like below:
The html code looks like this:
<div ng-model="wrapper_div" id="wrapper">
<input type="button" value="Update Data"
ng-click="updateData()" />
<ul ng-repeat="x in data">
<li>{{data}}</li>
</ul>
</div>
And the script:
var answers = [];
function updateData(data) {
var scope = angular.element($("#wrapper")).scope();
scope.$apply(function(){
answers.push(data);
scope.data = answers;
});
}
The expected result should look like:
9
6
7
And NOT this:
9,6,7
9,6,7
9,6,7

you are displaying data not x , data is an array , so complete array is displayed three time , instead display {{x}} try
<ul ng-repeat = "x in data"><li>{{x}}</li></ul>

You probably need to move your ng-repeat to the li tag, not the ul. and in the expression, use x and not data, which is why you are getting the whole array printed every time. so your html should look something like :
<div ng-model = "wrapper_div" id="wrapper">
<input type="button" value="Update Data" ng-click="updateData()"/>
<ul>
<li ng-repeat = "x in data">{{x}}</li>
</ul>
</div>

Related

Pass value from filter as argument for js function in angular

When I attempt to pass a value from ng-repeat into a function it seems to read the data literally from the text put in , whereas I would like to pass the values in....
<li ng-repeat="event in filtered = (events | filter:query) | orderBy:'-event_date'" >
<div class="event-info">
<strong>{{event.event_name}}</strong><br />
</div>
<div ng-click="prepare_edit('{{event.event_name}}')" >EDIT</div>
</li>
Controller:
$scope.prepare_edit = function(event_name) {
window.alert(event_name);
}
OUTPUTS: {{event.event_name}} , whereas I would like the actual value
You don't need to use braces {{}} in ng-click. If you have put "event" var inside $scope you can just use it.
<div ng-click="prepare_edit(event.event_name)" >EDIT</div>
Here is a FIDDLE

Conditionally setting orderBy Angularjs

I have an array of users, I want to have my ng-repeat ordered by last name when first loaded. After a new user is added have the ng-repeat ordered by dated added then last name. Essentially I want the newest users pushed to the top of the ng-repeat.
<th ng-click="menuFilter('lastName', 1);">
<div ng-class='{"menuSort":sortColumn==1}'>Name <span ng-show="share.orderByField == 'lastName'">
</div>
</th>
<tr ng-repeat="user in users | orderBy:orderByField:reverseSort"></tr>
In my JS...
_this.sortColumn = 1;
_this.orderByField = 'lastName';
_this.reverseSort = false;
_this.menuFilter = function(section, column) {
_this.orderByField = section;
_this.reverseSort = !_this.reverseSort;
_this.sortColumn = column;
};
//my attempt to reset the order by created at date
if( _this.isRefreshing ) {
_this.orderByField = ['createdAt', 'lastName'];
}
Basically this code is not doing anything. I think I am missing a step in the HTML.
Thanks!
I think this is easiest done by sorting the array in pure javascript and then using a ng-repeat without the orderBy attribute.
HTML:
<div ng-repeat="user in users">{{user}}</div>
<input type="text" ng-model="name"></input>
<button ng-click="addName()">Add name</button>
JS:
$scope.users = ["Rusty", "Shackleford", "Dale", "Gribble"];
$scope.users.sort();
$scope.addName = function() {
$scope.users.unshift($scope.name);
}
JSFiddle: http://jsfiddle.net/asWF9/2/
This answer may help to sort your array: https://stackoverflow.com/a/6712080/3675149
Try using "unshift" instead of 'push' to add an item into the array. The unshift in js enables us to insert an item to the top of an array.

Angular Checking What Filters Return

I have a list with ng-repeat and a filter , the filter filters based on an html input . If the filter produces an empty list , I want to show the user some informative message . I can't figure out how...
Search the list: <input type="text" ng-model="searchText">
<div ng-controller="my-ctrl">
<ul id="list">
<li ng-repeat="element in myElements | filter:searchText" >
{{element.data }}
</li>
</ul>
***<div>{{myElements.length}}</div>*** //length stays
// the same no matter what the filter is returning...
<div ng-show="myElements.length">My Informative Msg</div>
What I tried doing was showing my informative msg based on myElements.length , I thought that the filter will update the value of myElements in my scope . However , what I find as I search for items (e.g reducing or enlarging the list) is that myElements.length stays the same .
Is there some elegant solution to know when the filter is empty , or more generally to know what the filter is returning ?
There is a neat trick for that. Instead of filtering the real list, create a new filtered list "in the fly" which will contain only the filtered items or none. If none, show the message.
app.controller('MainCtrl', function($scope) {
$scope.items = ["Foo", "Bar", "Baz"];
});
And:
<input ng-model="searchText" />
<ul>
<li ng-repeat="item in filteredItems = (items | filter: searchText)">
{{ item }}
</li>
</ul>
<div ng-hide="filteredItems.length">There is no item matching</div>
So if your filter doesn't match any item, you will see the message.
Plunker here: http://plnkr.co/edit/3os7gIxSjlyDO1CGKcFT?p=preview
I think you should create your own filter which will do that.
Here it is: http://jsfiddle.net/QXSR8/
HTML
<div>
{{answer | empty}}
</div>
JS
angular.module('project', []).
filter('empty', function() {
return function(input) {
if (!input || !input.length){
return "Array is empty";
} else {
return input;
}
}
});

Angular factory filter - Can't get data passed to the filter

I'm looking through the Angular docs and I can't better documented stuff.
My problem is as follows:
I have a filter:
.filter('filteringService', function () {
return function (photos, categsList) {
if (photos !== undefined) {
var filteredPosts = [];
console.log('Categories or Selected Categories:');
console.log(categsList);
//DEVEL Only, assign a SEARCH value, can't pass the data from the list now.
categsList = 'people';
if (categsList === undefined) {
for(i=0; i < photos.length; i++) {
filteredPosts.push(photos[i]);
}
} else {
console.log('Trying to push a category slug to search for.');
//TASK: Convert in multiple possible selections.
filteredPosts = [];
}
console.log('Filter returns ' + filteredPosts.length + ' posts');
return filteredPosts;
}
};
});
And I have the template
<div class="photos">
<div class="filters">
<ul>
<li><a>ALL</a></li>
<li ng-repeat="category in categsList">
<a ng-checked="category[0]" ng-model="category[0]">{{ category[1] }}</a>
</li>
</ul>
</div>
<ul class="photos-list">
<li ng-repeat="photo in photos|filteringService:category">
<h1>{{ photo.title }} click LINK</h1>
<ul class="categories">
<li ng-repeat="category in photo.categories">
{{ category.title }}
</li>
</ul>
</li>
</ul>
</div>
There's a huge object with posts called photos and then there's a category list called categsList.
The photos object has the items from the categs list in it. I WANT to be able to filter with the CLICKED element through that list, and maybe multiple filter, but first to pass on the actual filter value to the filter service, I can't seem to do that.
How should I do that?
Apparently I managed to pass the filter value, in a dirty way (I GUESS), like this
<a ng-bind="category.slug" ng-click="returnFilter(category.slug);" ng-model="category.slug">{{ category.title }}</a>
it goes here
$scope.returnFilter = function(theSlug) {
$scope.filterBy = theSlug;
};
and it comes out here
<li ng-repeat="photo in photos|filteringService:filterBy">
It's working, but Is this correct?
EDIT: Also with this way in mind, I could pass an array as theSlug so I can do multiple filtering, and when clicking two times on the same item it would get it out of the array. hmmm
EDIT 2:
Let's say the resulting array is under 15 items, could do I run some action in the controller knowing this?
Actually the other way around, could I query from the controller the resulting array that the filter outputs?
I can't $watch the first array, I guess the filter creates a new array and puts those results in page. How could I watch the resulting array for changes and do stuff in the controller?

jQuery cloned list items all get the same text values while using each() function

I am trying to clone a list item in the DOM and append it multiple times depending on the number of text values in the variable data using the each function. The problem is that all the new list items get the same text values (all list items are set equal to the last appended list item).
I suppose it has something to do with enclosures, but I cannot figure it out.
Can anyone explain what the problem is?
Thanks!
data:
var data = {"text1": ["text1_row1", "text1_row2"], "text2": ["text2_row1", "text2_row2"], "text3": ["text3_row1", "text3_row2"] }
HTML:
<ul>
<li id="entryTemplate" style="display:none">
<span class="text1"></span>
<span class="text2"></span>
<span class="text3"></span>
</li>
</ul>
Javascript:
function listData(data){
$.each(data.text1, function(i) {
var newDataRow = $('#entryTemplate').clone();
newDataRow.removeAttr('id')
.removeAttr('style')
.removeAttr('class')
.addClass('copy')
.appendTo('ul')
.find('.text1').text(data.text1[i])
.find('.text2').text(data.text2[i])
.find('.text3').text(data.text3[i]);
});
}
$.fn.clone = function(){
var ret = $();
this.each(function(){
ret.push(this.cloneNode(true))
});
return ret;
};
Desired HTML:
<ul>
<li id="entryTemplate" style="display:none">
<span class="text1"></span>
<span class="text2"></span>
<span class="text3"></span>
</li>
<li class="copy">
<span class="text1">text1_row1</span>
<span class="text2">text2_row1</span>
<span class="text3">text3_row1</span>
</li>
<li class="copy">
<span class="text1">text1_row2</span>
<span class="text2">text2_row2</span>
<span class="text3">text3_row2</span>
</li>
</ul>
Result I get (all li items get the text for row2):
<ul>
<li id="entryTemplate" style="display:none">
<span class="text1"></span>
<span class="text2"></span>
<span class="text3"></span>
</li>
<li class="copy">
<span class="text1">text1_row2</span>
<span class="text2">text2_row2</span>
<span class="text3">text3_row2</span>
</li>
<li class="copy">
<span class="text1">text1_row2</span>
<span class="text2">text2_row2</span>
<span class="text3">text3_row2</span>
</li>
</ul>
Your question is a bit foggy and it's not really clear what's the result you're looking for. Appart from that I saw something in your code that's probably causing it. Give it a try and let me know what happened.
When you do
$.each(data.text1, function(i) {
change it to
$.each(data.text1, function(pos, element) {
and replace your [ i ] for [element].
According to JQuery API, when doing an EACH loop, the 1st return is the position in the array and the second is the value itself.
UPDATED ANSWER:
Your data object variable is formatted wrong... It looks like you want each value of the data object to be an array (using curly brackets implies you are defining an object with keys), so you should be using square brackets []. See array vs array-like object
var data = {
"text1": ["text1_row1", "text1_row2"],
"text2": ["text2_row1", "text2_row2"],
"text3": ["text3_row1", "text3_row2"]
}
jQuery already has a clone method so you shouldn't need to override with your own.
Based on the data you provided, you want to be iterating over the data variable itself, not data.text1. Then you can get the text values by value of the current index (this is the second parameter passed to .each()) and referencing [0] and [1] to get the actual text
$.each(data,function(i,value){
console.log(value);
var newDataRow = $("#entryTemplate").clone();
newDataRow
.removeAttr('id')
.removeAttr('style')
.removeAttr('class')
.addClass('copy')
.appendTo('ul');
newDataRow.children('.text1').text(value[0]); // value[0] == data[i][0]
newDataRow.children('.text2').text(value[1]);
});

Categories