I would like to know how to make controller function work whenever I change the state.
This is the main template of my Angular app:
<div>
<div ng-include="'/navigation.html'"></div>
<div>
<!-- Page wrapper -->
<div ng-include="'/topnavbar.html'"></div>
<!-- Main view -->
<div ui-view></div>
<!-- Footer -->
<div ng-include="'/footer.html'"></div>
</div>
</div>
In navigation panel I have ng-repeat:
<ul ng-controller="NavigationCtrl" class="nav nav-second-level">
<li ng-repeat="user in users" ui-sref-active="active">
<a ui-sref="account">{{user.name}}</a>
</li>
</ul>
So, whenever I change the state, I would like to update this scope var users.
I think this is well known problem, but I am new in Angular so help me please.
Well, I see two ways here:
1) Listening for state events, and do callback that updates user data. Docs here: https://github.com/angular-ui/ui-router/wiki#state-change-events
2) I assume that users array comes from service, something like:
...
$http.get('/users', function(data){
return data;
});
...
so, instead of this, you can store an array locally in service(which is singleton), and update it from any places, it that way you'll have a link to array in 'NavigationCtrl', and data will be updated there as well.
What I mean:
function UserService($http) {
var users = []; //inital array
var updateUsers = function() {
//get to update users here
};
var getUsers = fucntion() {
return users;
}
return {
updateUsers : updateUsers, //this method will be called when you need to update user list
getUsers : getUsers //this method will be called in NavigationCtrl
}
}
Update:
Here what I meant in pt.2 http://plnkr.co/edit/U2XwXNEqAxRrEa0VpYAu?p=preview
Related
Can we change the dom level child scope value using javascript function?
<article data-ng-init="show=true" data-ng-repeat="a in obj track by $index">
<div class="holder">
<div class="submit_btn" data-ng-bind="a.name" data-ng-click="ajaxCall(a,$event,show);"></div>
</div>
<ahref ="javascript:void(0)" data-ng-click="show=true></a>
</article>
####Controller
$scope.ajaxCall = function (obj,event,show){
//after ajax success togggle show
show = !show; //nothing is happening
};
I think you did just forgot a $scope...:
$scope.ajaxCall = function(obj, event, show) {
// on ajax call success, toggle $scope.show
$scope.show = !show; // something should happen... :-)
};
Right now show property shared by all article.So, whatever you do changes in it, will affect to all.
You can define html as follows.
Assign show property to each a object.
So,it will affect only respected article.
<article data-ng-init="a.show=true" data-ng-repeat="a in obj track by $index">
<div class="holder">
<div class="submit_btn" data-ng-bind="a.name" data-ng-click="ajaxCall(a,$event,a.show);"></div>
</div>
<ahref="javascript:void(0)" data-ng-click="sa.how=true">
</a>
</article>
And call ajaxCall method with a.show
This could help
$scope.show = [];
$scope.ajaxCall = function(obj, event, index) {
// after ajax success toggles show
$scope.show[index] = !$scope.show[index];
};
<div class="submit_btn" data-ng-bind="a.name"
data-ng-click="ajaxCall(a,$event,$index);"></div>
I'm moving my very first steps with angularjs.
I have a controller which does a call to a service, which returns a list of urls (parent).
I would like to render a html ul for which each li is rendered by another controller (children) with its own template. I imagine something like this:
<ul ng-controller="ListCtrl">
<li ng-repeat="element in elements">
<div ng-controller="DetailCtrl">
{{oneField}} - {{anotherField}}
</div>
</li>
</ul>
The first controller is easy to implement:
myApp.controller('ListCtrl', function ($scope, $http) {
$http.get('services/elements')
.success(function(data) {
$scope.elements = data;
});
});
But for the second I have a problem, since I can't figure out how the controller could know which url use for the ajax call (DYNAMYC_URL):
myApp.controller('DetailCtrl', function ($scope, $http) {
$http.get(DYNAMYC_URL)
.success(function(data) {
$scope.element = data;
});
});
Could you please suggest me which is the best way in angular to approach this problem?
I've also considered to do many calls inside the first controller, but it doesn't seem a clean solution to me.
We will try to maintain the state of childRenderUrl function call in element while
initializing the element itself in ng-unit attribute.
Instead of DetailCtrl
We write a function renderChild defined as
$scope.renderChild =function(element)
{
$http.get(element.url)
.success(function(data) {
// add all required fields to element here
element.otherField=data.otherField;
element.sometherField=data.sometherField;
//a $scope.$digest may be required here
});
}
Your display logic would be
<ul ng-controller="ListCtrl">
<li ng-repeat="element in elements">
<div ng-init="renderChild(element)">
{{element.oneField}} - {{element.anotherField}}
</div>
</li>
</ul>
On initializing we would call the renderChild method which would
add two properties to the element object that would be aptly displayed by
expressions {{element.oneField}} - {{element.anotherField}}
I have a status filed deep nested to 3 levels in my model, I want to apply different classes to a div based on the value of the status. In order the save the typing and keep the html tidy, I wanted to apply short name to this status so I used ng-init to copy the values and use ng-class on ng-init variable. But ng-init gets its value only once, when I change the status again in controller it doesnt change but holds the old value. Is there a way to give short names to response.obj1.obj2.status at least inside a div?
<div ng-app="app">
<div ng-controller="statusCtrl">
<button ng-click="toggle()">toggle</button>
<div id="section1" ng-init="s1Status=response.section1.status">
<div id="statusIndicator" ng-class="{'success':s1Status==0,'error':s1Status==1}">Status</div>
</div>
<span>{{response.section1.status}}</span>
</div>
var app = angular.module('app', [])
app.controller('statusCtrl', function ($scope) {
$scope.response = {
section1: {
status: 1
}
};
$scope.toggle = function () {
if ($scope.response.section1.status === 0) $scope.response.section1.status = 1;
else $scope.response.section1.status = 0;
}
});
Demo: http://plnkr.co/edit/ES7rgf97BPFAWzkfIEhw?p=preview
EDIT:
Knockout JS has nice way to do this, where you can bind a model at any level to a div and any models referred inside that div will work with the parnet model as context. Thats what I'm looking for.
<div id="section1" data-bind="response.section1">
<div id="statusIndicator" data-bind=" css:{success:status==0, error:status=1 }">Status</div>
</div>
Question:
How can I add a "Login" view/route to my angular app that hides an element that is outside the ng-view DOM?
Situation:
In my Angular page, I have a navigation tree view on the left and the main view in the center:
<div ng-app="myApp">
<div class="col-sm-3" ng-controller="TreeController">
<div treeviewdirective-here>
</div>
</div>
<div class="col-sm-9 content" ng-view="">
</div>
</div>
Each node in the treeview changes the location using something like window.location.hash = '#/' + routeForTheClickedItem;.
Using the standard routing, this works great, i.e. the tree is not reloaded each time, but only the main "window".
Problem:
I want to add a login functionality with a login view. For this view, the treeview should not be visible - only after the login. To achieve this with the normal routing, I know I could move the ng-view one level up, i.e. embed the treeview into each view - but this would result in the treeview being reloaded with every route change.
Is there an easy alternative that allows me to check what page is displayed in the ng-view? Or check some other variable set during the routing? Then I could use something like:
<div class="col-sm-3" ng-controller="TreeController" ng-show="IsUserLoggedIn">
You could listen for a routeChangeSuccess outside ng-view
$scope.$on('$routeChangeSuccess', function (event, currentRoute, previousRoute) {
//do something here
});
hope that helps, you can catch me on angularjs IRC - maurycyg
You could define a controller at the top div level.
Something like:
<div ng-app="myApp" ng-controller="MainController">
and in MainController inject a Session. Something like Session is enough to decide whether to show the tree.
Here's an example of MainController:
_app.controller('MainController', function ($scope, SessionService) {
$scope.user = SessionService.getUser();
});
Here's an example of SessionService:
_app.factory('SessionService', function() {
var user = null;
return {
getUser : function() {
return user;
},
setUser : function(newUser) {
user= newUser;
}
};
});
Of course, when you login you must set the user to the SessionService. Therefore, a SessionService has to be injected into your LoginController, too.
And finally, your html:
<div ng-app="myApp" ng-controller="MainController">
<div class="col-sm-3" ng-controller="TreeController">
<div ng-hide="user == null" treeviewdirective-here>
</div>
</div>
<div class="col-sm-9 content" ng-view="">
</div>
</div>
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