ng-init fetches value only once, even if the model value changes - angularjs

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>

Related

How can we get the child scope value in function and toggle it (Angular Js)?

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>

How do i select sibling Elements in AngularJS

I got a 4-5 rows of div ... when i click on any row it should change the selected one and color it as red and rest all to black ... i am using below logic but not working for me giving error as angular.min.js:117 TypeError: angular.element(...).siblings is not a function
Do i need to include jQuery file?
Can i do it without including jQuery file?
plz help
$scope.divClick = function($event){
console.log($event.target);
/* below siblings function not working for me*/
angular.element(event.target).siblings().css('color','black');
angular.element(event.target).css('color','red');
};
<div ng-controller="homeController">
<h1>Welcome</h1>
<div ng-repeat="x in json" ng-click="divClick($event)">
Name: {{x.Name}}<br/> City: {{x.City}}<br/> Country: {{x.Country}}<br/><br/>
</div>
</div>
Set your default color to be black.
<div ng-repeat="x in json" ng-class="{setRed: $index == value}" ng-click="divClick($index)">
Give CSS style to your class setRed.
Your controller function:
$scope.divClick = function(index){
$scope.value = index;
};
In general it's bad idea to modify DOM right from your controllers.
It's better to use scope or model properties and make decisions what class to apply based on them.
<div ng-repeat="x in json" ng-click="select($index)" ng-class="{'selected': $index == selectedIndex}">
Name: {{x.Name}}<br/>
City: {{x.City}}
Then you just have to update selectedIndex in you click handler
$scope.select = function(x) {
$scope.selectedIndex = x;
};
Fully working solution is here
https://jsfiddle.net/kvtcw8y6/4/
Other way is to have isSelected property on you model and update it accordingly.

Dynamically Show/hide directive

I am trying to implement some directive, which will be based on the value of one variable in other Service. Here is my code:
if (this.SomeService.variable.condition){
element.show();
} else {
element.hide();
};
However, it is called only once, when the page is bootstraped. How can I make it so that if the variable changes, the element shows/hides? Is there any way to do it without watcher?
You can use ng-show / ng-hide that are angularjs construct used to hide or show a particular piece of HTML.
For example:
<div ng-show="true">HELLO I AM THE FIRST DIV</div>
<div ng-hide="true">HELLO I AM THE SECOND DIV</div>
will return something like
HELLO I AM THE FIRST DIV
Inside ng-show you can put watherver kind of variable so then if your javascript is something like this:
angular.module('mymodule').controller('MyCtrl',[function(){
var self = this;
self.isVisible = true;
}]);
you can use that variable in your code:
<div class="container" ng-controller="MyCtrl as c">
<div ng-show="c.isVisible">HELLO I AM THE FIRST DIV</div>
<div ng-hide="c.isVisible">HELLO I AM THE SECOND DIV</div>
</div>
And the result is the same

Changing $scope variable value in controller not changing value on view

I am working on Cordova tool and angularjs for my application.
cordovaApp.controller("VacationCtrl", function ($scope, $http, $location) {
$scope.tempdate = "2222";
$scope.ruleDetails = function () {
$scope.tempdate = "3333";
}
});
view 1
<div ng-controller="VacationCtrl">
<a ng-repeat="data in rules" ng-click="ruleDetails()" class="summaryListBorder" href="#detailVacationRule">
</a>
</div>
view 2
<div ng-controller="VacationCtrl">
{{tempdate}}
</div>
In above given code, I sat value of $scope.tempdate to "2222". When I am click on link, it calls ruleDetails() and set $scope.tempdata = "3333". But when the new page is open with ng-view, it shows only old value, i.e. "2222". I want to change it with "3333". I have tried with $scope.$apply() too.
Thanks.
Every ng-controller attribute creates a new instance of the controller, which won't share the same scope as other instances. You want to wrap both divs in a single controller instance, like:
<div ng-controller="VacationCtrl">
<div>
<a ng-click="ruleDetails()" href="#detailVacationRule">
</a>
</div>
<div>
{{ tempdate }}
</div>
</div>
If you need separate controllers, then you want to move common functions/fields into a service, which operates as a singleton so you can use it to share information between controllers. Or you could contain the separate controller instances in a parent controller, which will hold common fields and can be accessed through each controller's scope.

Angular ng-show not working if parent has ng-if

I have a view where a parent div has ng-if on it, and some child element has ng-show on it. It seems that the ng-show isn't working correctly when nested under an element with ng-if on it. Is this an Angular bug or am I doing something wrong? See this plunker.
The HTML:
<!-- with ng-if on the parent div, the toggle doesn't work -->
<div ng-if="true">
<div>
visibility variable: {{showIt}}
</div>
<div ng-show="!showIt">
Show It
</div>
<div ng-show="showIt">
This is a dynamically-shown div.
Hide it
</div>
</div>
<br/><br/>
<!-- with ng-show on the parent div, it works -->
<div ng-show="true">
<div>
visibility variable: {{showIt}}
</div>
<div ng-show="!showIt">
Show It
</div>
<div ng-show="showIt">
This is a dynamically-shown div.
Hide it
</div>
</div>
The JavaScript:
scope.hideIt = function () {
scope.showIt = false;
};
Thanks,
Andy
Nemesv mentioned above that you should use $parent, but although working, this is not the right solution. The problem with this solution is:
It creates a high coupling between the scope from ng-if and the controller scope.
Because of 1, changing ng-if to ng-show will break your code.
As soon as your going to nest more scopes it becomes a mess ($parent.$parent.$parent....)
Solution:
The quick correct solution is to not define showIt directly on your scope, but instead place it in an object (e.g. component.isVisible).
Explanation:
To understand why this seemingly counter-intuitive solution works and is indeed the correct one you first need to know a little more about how inheritance works with angular:
Scopes inherit from each other using prototypal inheritance, which is the form of inheritance build in into Javascript. This looks as followed:
var myScope = {
showIt : false
}
var ngIfScope = {};
nfIfScope.__proto__ = myScope;
When you now get a property on the ngIfScope object that is not present there it will look in it's prototype to find it there. So if you request ngIfScope.showIt the browser does something like this:
if (ngIfScope.hasOwnProperty("showIt")) {
return ngIfScope.getOwnProperty("showIt"); // getOwnProperty does not actually exist in javascript
} else {
return ngIfScope.__proto__.showIt;
}
(in reality this happens recursively, but that's unimportant for this example).
Setting a property is much more straightforward though:
ngIfScope.setOwnProperty("showIt", newValue);
Now we have this information we can see what actually went wrong with your original implementation.
We started with the following scopes:
var myScope = {
showIt : false
}
var ngIfScope = {};
ngIfScope.__proto__ = myScope;
When the user clicks the show button the following code is executed:
ngIfScope.showIt = true;
and the resulting scopes are:
var myScope = {
showIt : false
}
var ngIfScope = {
showIt : true
}
ngIfScope.__proto__ = myScope;
As you can see the new value is written in ngIfScope, and not in myScope as you probably expected. The result is that ngIfScope.showIt overshadows the variable from myScope and myScope.showIt isn't actually changed at all.
Now lets see what happens if we place the visibility trigger in an object.
We begin with the new scopes:
var myScope = {
component : {
isVisible : false
}
};
var nfIfScope = {};
ngIfScope.__proto__ = myScope;
Not much changed so far. But now lets see what happens when the user clicks the button:
ngIfScope.component.isVisible = true;
With some helper variables we can see how this is executed in the browser:
var tempObject = ngIfScope.component;
tempObject.isVisible = true;
The first line here is a get operation. Since component is not defined on ngIfScope the Javascript engine will look at the prototype of ngIfScope (myScope) to find it there, as I explained above. Thus:
tempObject === ngIfScope.__proto__.component === myScope.component
We are now changing values directly on myScope.component, and hence the variables are not overshadowed this time. Resulting scopes are:
var myScope = {
component : {
isVisible : true
}
};
var ngIfScope = {};
var ngIfScope.__proto__ = myScope;
We now have a working implementation without explicitly binding to a $parent scope, and thus there is no (or little) coupling between the scopes. Prototypal inheritance does the work for us, and nested scopes work right out of the box as well.
Unlike ng-show the ng-if directive creates a new scope.
So when you write showIt = true inside the ng-if you are setting the showIt property on your child scope and not on your main scope.
To fix it use the $parent to access your property on your parent scope:
<div ng-if="true">
<div>
visibility variable: {{showIt}}
</div>
<div ng-show="!showIt">
Show It
</div>
<div ng-show="showIt">
This is a dynamically-shown div.
Hide it
</div>
</div>
Demo Plunker.
Use function or expression in the both cases, so this variant is working.
<div ng-if="true">
<div>
visibility variable: {{showIt}}
</div>
<div ng-show="!showIt">
Show It
</div>
<div ng-show="showIt">
This is a dynamically-shown div.
Hide it
</div>
</div>
And this variant also
<div ng-if="true">
<div>
visibility variable: {{showIt}}
</div>
<div ng-show="!showIt">
Show It
</div>
<div ng-show="showIt">
This is a dynamically-shown div.
Hide it
</div>
</div>
with the code
$scope.changeState= function (state) {
$scope.showIt = state;
};
So what Tiddo said about Namesv is true, but also overtly complex.
This'll do it:
scope.pageData = {};
scope.hideIt = function () {
scope.pageData.showIt = false;
};
Containing showIt in an object on the parent scope will ensure it's the same object when using it in children scopes

Resources