AngularJS , small trick - angularjs

I've got one question . Is there anybody how has idea how to invoke function in controller only for the first li object in ul when ul has a ng-repeat?
Lets say ive got function in my controller like:
var init = function () {
var a = this;
};
And my ul repeater seams like lets say:
<ul ng-repeat="up in userpartners" ng-click="setSelected(this);">
<li>
{{up.id}}
</li>
</ul>
And I want to invoke init function with parameter 'this' which will be first 'li' item. Only for the first li i want to set something.

You can do it like this:
<ul ng-repeat="up in userpartners" ng-init="init(up, $first);">
<li>
{{up}}
</li>
</ul>
And in the controller:
$scope.init = function (item, isFirst) {
if (isFirst) {
alert(item);
}
};
Fiddle Example

See here check if $index is zero or $first is true.

But there's already a single LI inside your UL.
I believe you mean:
<ul>
<li ng-repeat="up in userpartners" ng-init="$first && setSelected(up)">
{{up.id}}
</li>
</ul>
or
<ul ng-init="setSelected(userpartners[0])">
<li ng-repeat="up in userpartners">
{{up.id}}
</li>
</ul>
See the difference? We want to repeat the children, not the whole list.
Although I believe it wouldn't be a good practice to have this call on a view. I'd put it inside a controller, the call itself.

Related

AngularJS - Change scope with one of the iterations of a ng-repeat

I have a project with Angular where I don't want to use a select element with ng-options, so I made up a list with different options in order to select one of them.
<div class="countrylist">
<ul>
<li ng-repeat="c in shippingCountry"><p>{{c.name}}</p></li>
</ul>
</div>
So the option selected would modify another element where the chosen option would be displayed.
<div>
<ul>
<li>{{selectedCountry}}</li>
</ul>
</div>
In order to do that, I would need to pass the data from the chosen option of the first element into the 2nd one. I have tried doing something like this
<li ng-repeat="c in shippingCountry" ng-click="selectedCountry = {{c}}"><p>{{c.name}}</p></li>
with no success.
You can check the plunker here Thanks in advance
I suggest you to use a function over there like this in the DEMO
<li ng-repeat="c in shippingCountry" ng-click="Click(c)"><p>{{c.name}}</p></li>
Having this method in your controller
$scope.Click=function (c)
{
$scope.select=c;
}
It creates child scope for each iteration, so explicitly refer parent scope:
Change like this,
<ul>
<li ng-repeat="c in shippingCountry" ng-click="$parent.selectedCountry = c"><p>{{c.name}}</p></li>
</ul>
DEMO
I've fixed your plunker here. It would be better to use methods in scope for this operations because they work in current scope, not in child
<li ng-repeat="c in shippingCountry" ng-click="selectCountry(c)">
<p>{{c.name}}</p>
</li>
// .html
<div>
<ul>
<li>{{selectedCountry.item}}</li>
</ul>
</div>
<div class="countrylist">
<ul>
<li ng-repeat="c in shippingCountry" ng-click="selectedCountry.item = c"><p>{{c.name}}</p></li>
</ul>
</div>
// controller
$scope.selectedCountry = {
item: $scope.shippingCountry[0]
};
Example

Remove parent li after click child image

I want to remove the parent li when I click on the child image using angular. Here's what I have so far:
View
<ul class="cg-tag-list">
<li ng-repeat="tag in list">
<span>{{tag}}</span>
<img src="" ng-click="fnRemoveTag()"/>
</li>
</ul>
JS
//Remove Tag
$scope.fnRemoveTag = function () {
// Put Code here
}
pass the tag to the fnRemoveTag function;
<ul class="cg-tag-list" >
<li ng-repeat="tag in list">
<span>{{tag}}</span>
<img src="" ng-click="fnRemoveTag(tag)"/>
</li>
</ul>
$scope.fnRemoveTag = function (tag) {
// get the index of the tag which we are going to remove
var index = $scope.list.indexOf(tag);
// remove that tag from the `list` array
$scope.list.splice(index, 1);
//this will automatically update the dom for you
}
here is a DEMO
and note that you can pass the $index of the instead of tag like
<img src="" ng-click="fnRemoveTag($index)"/>
and remove the element in controller as,
$scope.fnRemoveTag = function(index) {
// remove that tag from the `list` array
$scope.list.splice(index, 1);
//this will automatically update the dom for you
}
example DEMO
if you don't use the orderBy in the ng-repeat then use the $index other vise use the tag, because if you use orderBy it will sort the array according to sort description and when you pass the $index it may not the correct index of $scope.list.
for EX:
say you have array like $scope.list = [3, 2, 1]; and you need to ng-repeat this with order by
<li ng-repeat="tag in list | orderBy:tag">
after the orderBy, ng-repeat will repeat the sorted array, but actually $scope.list remain as before & it will not gonna sort only the repeat order gets change.
so $index is the ng-repeat's index and its not represent the index of $scope.list, if you do not use the orderBy then both will be same.
then when you try to remove from the $scope.list with the passed $index it will may not remove the correct element.
see this DEMO
try to remove first one and note that it actually remove the last one. because we pass the $index as 0 to the function and remove the 0th index element of the $scope.list which has value of 3.
hope that makes sense.
View
<ul class="cg-tag-list" >
<li ng-repeat="tag in list">
<span>{{tag}}</span>
<img src="" ng-click="fnRemoveTag(tag)"/>
</li>
</ul>
JS
//Remove Tag
$scope.fnRemoveTag = function (listItem) {
var index = $scope.list.indexOf(listItem);
if (index > -1) {
$scope.list.splice(index, 1);
}
}
if you have jQuery you can use this:
var li = $(this).closest("li");
li.parent().remove(li);
Simply put $index as function parameter then use array splice method.
View
<ul class="cg-tag-list" >
<li ng-repeat="tag in list">
<span>{{tag}}</span>
<img src="" ng-click="fnRemoveTag($index)"/>
</li>
</ul>
Javascript (don't use orderBy filter in this purpose)
$scope.fnRemoveTag = function (index) {
$scope.list.splice(index, 1);
}

Angular ng-class code

I am very new to Angular and I have this piece of code:
<nav ng-controller="navController">
<ul>
<li ng-class="{'active': location('/') || location('/homepage')}">
view puppies
</li>
</ul>
</nav>
With the corresponding controller:
obApp.controller('navController', function($scope, $location) {
$scope.location = function(loc){
if(loc == $location.path()){
return true;
}else{
return false;
}
}
})
Now everything works fine. When I'm on the homepage the list element gets the class active added to it, HOWEVER there is also the angular ng-class directive code shown in the source, like so (this is the HTML source output of the browser):
<li ng-class="{'active': location('/') || location('/homepage')}" class="active">
view puppies
</li>
Should the list element not look like: <li class="active">view puppies</li> ? Logic would dictate that it should look like it is now, because ng-controller="x" shows in the source as it is as well. However that's a hook if you will. The other one's an expression. It looks funky and I'm not sure if it's ok or not. Please, if you answer, detail your answer.
There is nothing wrong with your code, ng-class directive doesn't remove the attribute ng-class from the element when the expression evaluates to true, since you could have more than one expression/class in your ng-class attribute value.
Additionally if the directive did remove the attribute (ng-class) angular would have no way of knowing that you have applied that directive to the element. For example, your element had ng-if on it, it would be removed from the DOM and appended conditionally.
Example
ng-class="{'active': location('/') || location('homepage'), 'disabled': location('private'))}"
Such usage of ng-class is non-effective because $scope.location method will be called at least twice (for location('/') and location('homepage')) each digest loop. There could be a lot of digest loops due to balancing mechanism.
Better approach is to calculate if element is active on location change.
Controller:
$scope.$on('$locationChangeSuccess', function(){
$scope.isHomePage = location('/') || location('/homepage');
});
Markup:
<nav ng-controller="navController">
<ul>
<li ng-class="{'active': isHomePage}">
view puppies
</li>
</ul>
</nav>

Angular : How to load images through XHR request in ng-repeat loop

I am trying to create a contact book in which every person can have a photo.
As I would like to display the contact before getting its photo, I would write something like
<ul>
<li ng-repeat="person in persons">{{person.firstname}} {{persone.lastname}}</li>
</ul>
I would try to call a get_photo(person) available in my scope.
<ul>
<li ng-repeat="person in persons">{{person.firstname}} {{persone.lastname}}
<img ng-src="{{get_photo(person)}}" />
</li>
</ul>
Which doesn't work because it binds the function to ng-src and call get_photo every time ng-repeat is called.
I finally tried to call get_photo when initializing the DOM element and store the result in a specific attribute photo
<ul>
<li ng-repeat="person in persons">{{person.firstname}} {{persone.lastname}}
<img ng-init="get_photo(person)" ng-src="{{person.photo}}" />
</li>
</ul>
$scope.get_photo = function (person) {
// Simple example; I will try to get an image through xhr request later...
person.photo = "http://img.blogduwebdesign.com/benjamin-sanchez/737/AngularJS.jpg";
};
Is there an easier / cleaner way to do the same ?
I also created a jsFiddle : http://jsfiddle.net/V4Mss/
Thanks a lot for your feedback !
t00f
Your last example seems fine but here is another option that keeps the view a little cleaner and doesn't cause the double $digest. Remove the initialization function from each element and use the function as a getter.
HTML
<img ng-src="{{person.photo}}" />
JavaScript
myapp.controller('controller', function ($scope) {
$scope.count = 0;
$scope.get_photo = function (person) {
return "http://img.blogduwebdesign.com/benjamin-sanchez/737/AngularJS.jpg";
};
$scope.persons = [{firstname:"toto", lastname:"TOTO", photo:$scope.get_photo()},
{firstname:"tata", lastname:"TATA", photo:$scope.get_photo()},
{firstname:"titi", lastname:"TITI", photo:$scope.get_photo()}];
});
Here is a fiddle

How do I use ng-class without ng-repeat?

I am relatively new to AngularJS and am loving every moment of it! I have an unordered list of products. When the user hovers over them, I need the list element to have an active class set on them. I am currently doing it this way:
<ul>
<li ng-repeat="product in products" ng-mouseover="showDetails(product, $event)" ng-class="{active: current == product}">{{product}}</li>
</ul>
And my showDetails is as follows:
function showDetails(product, $event) {
$scope.current = product;
...some other logic...
}
Now, everything is working just fine, however, I was wondering if it was possible to set the class without the ng-repeat and having no product variable to bind to?
<ul>
<li ng-mouseover="showDetails($event)" ng-class="{<i don't know what to put here> }">foo</li>
<li ng-mouseover="showDetails($event)" ng-class="{<i don't know what to put here> }">bar</li>
<li ng-mouseover="showDetails($event)" ng-class="{<i don't know what to put here> }">A</li>
<li ng-mouseover="showDetails($event)" ng-class="{<i don't know what to put here> }">B</li>
</ul>
How should I write my showDetails function to set the class this time? My first try is:
function showDetails($event) {
var text = $event.target.textContent;
$scope.current = text
}
But what do I do in the ng-class attribute?
If a pure CSS solution is not possible then you can create a directive and toggle a CSS class using JQuery within that directive. Apply the directive on the ul as an attribute or class. In that directive you can do
iElement.find("li").hover(...

Resources