Controller scope share? - javascript

I have in my index.html two separate places where I declare:
<div ng-controller="ParentController>
<div id="box1" ng-controller="SameController">
Box1 {{test}} <button ng-click="changeMe()">Click</button>
</div>
<div id="box2" ng-controller="SameController">
Box2 {{test}}
</div>
</div>
Initially in SameController, $scope.test = "One"
I want to make it so that when the user clicks the "Click" button, then {{test}} text will change to "Two" in both places (box1 and box2) (what the changeMe function does).
The problem is when I click, only the message in "Box1" changes to "Two", but not the message in "Box2". I tried using: $scope.$parent.test = "One" and make it so that SameController points to it, but it does not seem to work either.
How can I get around this so that both box1 and box2 change the text content of {{test}} when the button is clicked? The more elegant the solution the better.

Each element with ng-controller directive has its own scope, and they are not connected in any way. The most elegant solution is to set up a service for common application data.
app.value('commonData', {});
app.controller('SameController', function ($scope, commonData) {
$scope.data = commonData;
$scope.changeMe = function () {
$scope.data.test = 'test';
}
});
And use it like this
<div ng-controller="ParentController>
<div id="box1" ng-controller="SameController">
Box1 {{data.test}} <button ng-click="changeMe()">Click</button>
</div>
<div id="box2" ng-controller="SameController">
Box2 {{data.test}}
</div>
</div>
You can also hold common data in parent scope, but it is not recommended because both SameController are forced to be direct descendants of the same parent directive this way.

Related

Losing scope when using ng-include for recursion ( Updating object at run time, not reflecting the changes on child template) in angularjs

I'm using ng-include for recursion. it's loading correct at first time but when I change anything in the object at run time, it doesn't reflect the changes on html. ng-include will create a child scope for that, so its not getting changes from parent scope. How can I bind the scope or reflect the changes in the html? Below is the code snippet for main.html
<div ng-switch on="value.length>0">
<div ng-switch-when="true">
<div ng-init="item = value[0];" ng-include="'test/views/partialTemp.html'">
</div>
</div>
</div>
In Partial Template
<div class="row" ng-repeat="(key, result) in item" ng-if="item ">
.......
<div ng-switch on="result.length > 0 ">
<div ng-repeat="tempValue in result">
<div ng-switch-when="true">
<div ng-init="item = tempValue;" ng-include="'test/views/partialTemp.html'"></div>
</div>
</div>
</div>
....
</div>
In JS File
onRadioButtonChange = function(key, value, item) {
var self = this;
self.serviceObj.Response.values = self.updateServiceObject(self.serviceObj.Response.values, key, value, false); // Updating the actual object which came from service
self.objectToShow = JSON.parse(JSON.stringify(self.serviceObj)); // Taking the actual object which will show in the HTML
self.objectToShow.Response.values = self.filterObjectToShow(self.objectToShow.Response.values); // it'll add/remove the child radio button
}
objectToShow is the object which I'm using to render the html

Angular JS view hasn't been updated properly

I have found an issue in AngularJS which relates to wrong update of view. It occurs from time to time. The problem is when model gets a new value, view is not updated by new model value, but old value is appended by new model value.
While troubleshooting I checked that model contains a correct value.
Here is a view.
<div class="container">
<div ng-repeat="p in point" id="{{'point-' + p.Id}}" class="{{p.BackgroundClass}}">
<div class="point-number">{{p.Id}}</div>
<div class="{{p.ImageClass}}"></div>
<div class="point-amount">{{p.Amount}}</div>
<div class="point-quantity">{{p.Quantity}}</div>
</div>
</div>
Controller code which contains SignalR events processing:
wetApiHubProxy.on('updatePointState', function (pointId, backgroundClassProp, imageClassProp) {
pointsService.getPointById(pointId).then(function (point) {
point.BackgroundClass = backgroundClassProp;
console.log('imageClassProp ' + point.ImageClass);
point.ImageClass = imageClassProp;
});
});
p.ImageClass is changing quite often. Changes/updates of view work in a correct way until sometimes occurs concatenation of old and new value.
Old p.ImageClass value is "point-state-configure".
New p.ImageClass value is "pump-state-off".
As a wrong result I have, where ImageClass contains concatenated values:
<div ng-repeat="p in points" id="point-4" class="point point-off" role="button" tabindex="0" style="">
<div class="point-number ng-binding">4</div>
<div class="point-state-configure pump-state-off" style=""></div>
<div class="point-amount ng-binding">926.93</div>
<div class="point-quantity ng-binding">417.35 L</div>
</div>
I have tried to call $scope.$apply() and $evalAsync, but that was hopeless. The strangest thing that issue occurs spontaneously. The only constant condition it's when $rootscope contains bigger amount of child scopes. Can anyone tell what place to dig and how to get rid of this problem?
class attribute is not intended to be used this way. You should use the ng-class directive instead.
I've created an example for you: https://jsfiddle.net/coldcue/o7q6gfs4/
JavaScript
angular.module('testApp', [])
.controller("TestController", function($scope) {
// Initialize the value
$scope.state = "state-blue";
// Change class on click
$scope.click = function() {
$scope.state = ($scope.state === "state-blue") ? "state-red" : "state-blue";
}
});
HTML
<div ng-controller="TestController">
<div ng-class="state">
Some label
</div>
<input type="button" ng-click="click()" value="Click me">
</div>
But there are many more ways to use ng-class, read more here: https://docs.angularjs.org/api/ng/directive/ngClass

How do I access this scope variable inside of isolated scope directive?

This is my situation in psuedo code
<div data-ng-controller="test">
<div isolated-directive>
<select ng-model="testControllerScopeVar">...</select>
</div>
<div ng-if="some condition that uses testControllerScopeVar"></div>
</div>
This worked perfectly before I added isolated-directive, now that it is added (scope: true) the ng-if no longer works because I think it is getting eat up inside of the directive.
What is the most efficient way to get this working without touching the structure of the html and isolated-directive?
Well it seems once I know the solution, it is so simple
<div data-ng-controller="test as testCtrl">
<div isolated-directive>
<select ng-model="testCtrl.testControllerScopeVar">...</select>
</div>
<div ng-if="testCtrl.testControllerScopeVar == 'whatever'"></div>
</div>
ControllerAs allows me to specifically access the right scope and works perfectly, thanks all for your time and input
One approach is to map the controller variable into your isolated scope and attach the isolated scope variable to your internal ng-model.
So your HTML would look like this:
<div data-ng-controller="test">
<div isolated-directive="testControllerScopeVar">
<select ng-model="isolatedScopeVar">...</select>
</div>
<div ng-if="some condition that uses testControllerScopeVar"></div>
</div>
And your directive declaration would look like this:
app.directive('isolatedDirective', function () {
return {
scope: {
isolatedScopeVar: '=isolatedDirective'
}
};
});
You can try jQuery to get the value and assign it to a new scope variable. Something like this
HTML
<div ng-app="TestApp">
<div data-ng-controller="test">
<div isolated-directive>
<input id="isolatedVar" ng-model="testControllerScopeVar" />
</div>
<div>
{{isolatedVar}}
</div>
</div>
</div>
JS
var app = angular.module('TestApp', []);
app.controller('test', function($scope) {
var element = angular.element(document.querySelector('#isolatedVar'));
element.bind('keyup', function() {
$scope.isolatedVar = element.val();
console.log($scope.isolatedVar);
$scope.$watch('isolatedVar', function() {});
});
});
app.directive('isolatedDirective', function() {
return {
scope: true
};
});
Working fiddle https://jsfiddle.net/kavinio/yzb8ouzd/1/

Remove Class AngularJS

Spent some time searching for an answer to this, grabbed a few lines of different sample code and it just errors out as well.
Goal:
Click a button > button adds class "active" to a div. Inside the div.active there is another element with a function to remove .active from div.active
HTML:
<body ng-app="myApp">
<div ng-controller="myCtrl">
<button ng-click="slidePanel='active'">Open Div 1</button>
<div class="div1" ng-class="slidePanel">
<div class="close" ng-click="removeActive()">Close</div>
Hi I'm a Slide Panel
</div>
</div>
</body>
JS:
angular.module('myApp', [])
.controller('myCtrl', ['$scope', function ($scope) {
$scope.removeActive = function () {
//Errors with Element is not defined
/*var myEl = angular.element(element.getElementsByClassName('div1'));
myEl.removeClass('active');*/
//Errors with myEl.removeClass is not a function
var myEl = document.getElementsByClassName('div1');
myEl.removeClass('active');
//Errors with [jqLite:nosel] Looking up elements via selectors is not supported by jqLite!
/*var myEl = angular.element('div1');
myEl.removeClass('active');*/
//Errors with Element is not defined
/*var query = element[0].querySelector('.div1');
var wrappedQueryResult = angular.element(query);
query.removeClass('active');*/
}
}]);
Not sure what I'm doing wrong here.
FIDDLE
Solution is simpler if you use object syntax for ng-class
<button ng-click="slidePanel=!slidePanel">Toggle Div 1</button>
<div class="div1" ng-class="{active:slidePanel}">
<div class="close" ng-click="slidePanel=!slidePanel">Toggle</div>
Hi I'm a Slide Panel
</div>
DOM manipulation should not be done in a controller. Always think scope first, angular has a huge array of tools to manage the dom based on scope models
What ng-class="{active:slidePanel} is doing is toggling the class active based on the expression slidePanel
DEMO
If you don't want to use object notation (which would be my preferred method), you could also just set slidePanel back to an empty string to remove the class.
<div class="close" ng-click="slidePanel=''">Close</div>

ng-click not working with ng-if angularjs

I am trying to toggle a div on button click like as bellow.
This is working.
<div>
<button ng-click='x = ! x'>toggle</button>
</div>
<div ng-include="'pages/include/search.html'" ng-show='x'></div>
This is not working.
<div ng-if="$state.current.url!='/splash'" >
<button ng-click='x = ! x'>toggle</button>
</div>
<div ng-include="'pages/include/search.html'" ng-show='x'></div>
Why it is not working, when I add ng-if="$state.current.url!='/splash'" ?
Well,
Every angular directive create new scope
In the code below
<div ng-if="$state.current.url!='/splash'" >
<button ng-click='x = ! x'>toggle</button>
</div>
<div ng-include="'pages/include/search.html'" ng-show='x'></div>
The ng-if directive create new scope.And withing this scope
the value of x is updated on button click.But this new value of x is not accessible outside this ng-if div as it is local to that scope and it is primitive type.
Since this x is primitive type so there is no data update as reference are differant.
You should use object model instead.
Here is the updated HTML
<div ng-if="$state.current.url!='/splash'" >
<button ng-click='x.showHide = ! x.showHide'>toggle</button>
</div>
<div ng-include="'pages/include/search.html'" ng-show='x.showHide'>This is div</div>
define x like this one in your controller.
$scope.x = {showHide:false}
EDIT-
In your first woking HTML, there is not directive on div.So, both these DIV come under same scope.So,x accessible across this two DIV with updated value.
<div>
<button ng-click='x = ! x'>toggle</button>
</div>
<div ng-include="'pages/include/search.html'" ng-show='x'></div>

Categories