Repeat over a collection of Prototypes - angularjs

I have a collection of Prototype instances that I ng-repeat over.
The current solution I found is from here https://groups.google.com/forum/#!topic/angular/rdMf0DZHVvE
I basically define a controller on the ng-repeat directive and then initialize the prototype in there something like this:
<li ng-repeat="user in users" ng-controller="MyUserExtender">
{{user.name}}
</li>
The controller then extends the user:
controllers.controller('MyUserExtender', function($scope) {
$scope.user = new User($scope.user);
});
For the complete code please see here:
http://jsfiddle.net/5d5v6b5j/
The problem now is, if I change the name of a user via. ng-model for example, the ng-repeat does not update and the user-name that is output stays the same.
Thank you for your input cheers
christoph

It's dead simple, just pass in an array of allready initialized prototypes.
var users = [new User({name: 'test'})];
<li ng-repeat="user in users"></li>

Related

how to call a value from array in AngularJS controller?

I have an array like this:
$scope.persons = [{name:'Joey', age:'27'}]
I can call the value in HTML in this way
{{person.name}}
But when I try something like this, it fails
$scope.name = $routeParams.person.name
I could read the person only (without .name), it will be displayed as an array.But I want to access to the name key. Thx in advance.
I pass the person to JS in this way (route)
<tr data-ng-repeat="person in persons">
<td headers="more">
Show Details
</td>
</tr>
Try below code, as you are accessing value from array, whenever you access value from array need to mention index.
$scope.name = $routeParams.persons[0].name
Try This
Show Details

How to update $index when list changes in angular

I'm trying to implement a keyboard navigation in a multi-level List.
Therefor i try to give every Item in the List a unique ID, like 5.2.1(category.item.subitem).
I already tried a lot of stuff, like ng-init the index to a variable on ng-repeat, an other approaches using directives, but all had the problem so far that when i change the list (delete items for example) my Custom Index doesn't update!
I made a simple Plnkr here:
You can delete an item or subitem and see that the "real" index and the customindex don't relate.
http://plnkr.co/edit/BsRCNAqM7jWkeAJ9rkLN?p=preview
at the moment i have a custom directive called customIndex that gets the Index as attribute.
<li ng-repeat="subitem in item.subitem" custom-Index="$parent.$index+'.'+$index">
and inside the directive i simply $eval the attribute:
.directive('customIndex', function(){
return{
restrict:'A',
link: function(scope, el, attrs){
scope.myIndex = scope.$eval(attrs.customIndex);
}
}
})
But this, like all other solutions i tried, doesn't work.
I think this must be a common kind of problem.
Does anyone have any suggestions for me?
THANKS
Markus
I think you overcomplicated yourself. Try only this piece of markup and no need for custom directive or something else:
<ul>
<li ng-repeat="item in data">
"Real"-index:{{$index}} | myIndex:{{myIndex = $index}}} | Item:{{item.itemName}} <button ng-click="data.splice(data.indexOf(item),1)">Del</button>
<ul>
<li ng-repeat="subitem in item.subitem">
"Real"-index:{{$index}} | myIndex:{{myIndex = $parent.$index+'.'+$index}} | Subitem:{{subitem}} <button ng-click="item.subitem.splice(item.subitem.indexOf(subitem),1); ">Del</button>
</li>
</ul>
</li>
</ul>
ng-init will never work for you because it is executed only when directive is compiled. With custom directive it will never work because the scope item will be of the item that you delete and you dont' have access to the entire list.
Here is the demo:
http://plnkr.co/edit/Nr4cJ2m3JqI8NyLFnQhC?p=preview
so, in the meantime i found a solution. Maybe not the best, but it works.
i could attach the needed parameters to a directive attribute and set a $watch on this attribute to stay synchronised with any changes caused by deleting/filtering etc.
for example:
<div item-Index="[$parent.$index,$index,-1,$first, $last]"</div>
and the directive hast the following function in the link function:
scope.$watch(attrs.itemIndex, function(value) {
scope.itemIndex = value;
});
now every item has a unique index defined.
The multilevel keyboard navigation also works now, but this is beyond the scope of this question.

AngularJs- how to combine two $scope properties in the view and order by timestamp?

Say I have $scope.someItems which looks like {key1a: {val:'someval', time:timestamp}, key2a: {val:'someval', time:timestamp}, key3a: {val:'someval', time:timestamp} }}
I also have a second object $scope.moreItems which looks like {key1b: {val:'someval', time:timestamp}, key2b: {val:'someval', time:timestamp}, key3b: {val:'someval', time:timestamp} }}
In the view, I want to display the all the item val's in $scope.someItems and $scope.moreItems in a list ordered by timestamp (time property).
How would you accomplish this, only through the view code, assuming you have no access to modify the controller (so one cannot combine objects in the controller etc.).
As #tymeJV comment states this should be done in the controller (remember angular.js controllers are actually the viewModel layer since angular isn't an mvc but an mvvm - So It's perfectly correct to handle this data view manipulation there, without changing the data source, stored in a controller). But if you feel you must do it view code then you can Use a Directive!
just pass the directive both arrays as attrs. in the directive combine the lists and take care of ordering, filtering etc. then you can just use the Directive in the view template! very angularish solution (For a problem you probably invented)
I don't think this is possible only with view code.
I would use some library like lodash or underscore and do it in the controller:
http://jsfiddle.net/WRtqV/304/
<div ng-app ng-controller="MyCtrl">
<ul>
<li ng-repeat="(key, value) in allItems">{{key}}: {{value | json}}</li>
</ul>
</div>
function MyCtrl($scope) {
$scope.someItems = {key1a: {val:'someval', time:1234}, key2a: {val:'someval', time:324234}, key3a: {val:'someval', time:54234} };
$scope.moreItems = {key1b: {val:'someval', time:2423423}, key2b: {val:'someval', time:234234}, key3b: {val:'someval', time:54353453} }
$scope.allItems = _.extend($scope.someItems, $scope.moreItems);
}

How do I call an angular function from within an angular function?

I have written an angular function that works fine. Now, I want to write another angular function that calls the first function. How can I do this?
app.controller("AppCtrl",function($scope,$location,$http,$compile,$rootScope){
$scope.func1 = function(param1,param2){
... // function body
};
$scope.func2 = function(param3) {
var value = "someValue";
$scope.func1(value,param3);
};
});
Unfortunately func2() doesn't work, even though fucn1() works if I call it directly (e.g., <div ng-click="func1(val1,val2)">Click Here</div>. Why?
UPDATE:
It's because I'm doing the following:
<ul>
<li ng-click="func2('{{item.value}}') ng-repeat="item in items">Item</li>
</ul>
For some reason {{item.value}} is not being compiled in the ng-repeat. I can inspect the HTML and see that the values are there, but the ng-click doesn't do anything. However, if I manually enter a value for the parameter in func2, then it works. So, now my questions is: How do I compile items in an ng-repeat?
I fixed your example here: http://jsfiddle.net/CsffM/
The problem is that you are using brackets in your expression,
Insted, do this:
<li ng-click="func2(item.value)" ng-repeat="item in items">Item</li>
I hope I have helped!

How can I obtain the result array of an angular "| filter" expression in a variable?

In angular, you can write filter expressions like
<input type="text" ng-model="query">
<table>
<tr ng-repeat="phone in phones | filter: query">
<td>{{phone.vendor}}</td>
<td>{{phone.model}}</td>
</tr>
</table>
and it will update the table to show only the phones which match the query text you enter into the input.
How can I get the corresponding result array of the filter, e.g. the [phone object]s that are currently displayed, in a variable (e.g. a scope variable)?
You can actually assign new variables to the scope in an angular expression. So the simplest solution would be to do <tr ng-repeat="phone in (filteredPhones = (phones | filter: query))">. filteredPhones is now a variable in the current scope - see this plnkr example.
Inside your controller, you can watch changes to your query text and use the Javascript equivalent of {expression} | filter: {expression}, which is $filter('filter') (using the filter named 'filter' from the service $filter, which you have to inject).
Let's say your HTML snippet is controlled by the controller MyController. Then you can change it to:
myApp.controller("MyController", ["$scope", "$filter", function($scope, $filter) {
$scope.$watch('query', function(newVal, oldVal) {
console.log("new value in filter box:", newVal);
// this is the JS equivalent of "phones | filter: newVal"
$scope.filteredArray = $filter('filter')($scope.phones, newVal);
});
}]);
Whenever your query changes, the filtered array will be available as filteredArray in your $scope, and you can use filteredArray as an expression in your snippet.
All this should actually be documented in http://docs.angularjs.org/api/ng.$filter and http://docs.angularjs.org/api/ng.filter:filter. However, the documentation of the first link is way too sparse you can really only get it from the comments to the second link. I tried to add it to the docs, but after cloning angular and building the docs, accessing them via the browser simply did not work and navigating the API failed silently without any useful error, so I gave up on that.

Resources