Passing data via service not updating second controller - angularjs

I am trying to use service in AngularJS and pass data from one controller to another on click of a button.
I tried and can see that service value is updated but I am unable to retrieve in the second controller, however, I can retrieve in the first Controller.
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="myCtrl">
<p>Search:<input type="text" ng-model="newValue"></p>
<button ng-click="myFunc(newValue)">OK</button>
</div>
<div ng-controller="myCtrl2">
{{receivedVal}}
</div>
<script>
var app= angular.module('myApp', []);
app.controller('myCtrl', function($scope,sharedProperties) {
$scope.stringValue = sharedProperties.getString();
$scope.myFunc = function(newValue) {
sharedProperties.setString(newValue);
$scope.stringValue = sharedProperties.getString();
console.log($scope.stringValue);
//I am getting the value here by calling sharedProperties.getString();
};
});
app.controller('myCtrl2', function($scope,sharedProperties) {
$scope.receivedVal = sharedProperties.getString();
console.log($scope.receivedVal);
//But I am not getting the updated value here by calling sharedProperties.getString();
});
app.service('sharedProperties', function() {
var stringValue = 'firstoccurence';
return {
getString: function() {
return stringValue;
},
setString: function(value) {
stringValue = value;
},
}
});
</script>
</body>
</html>
receivedVal is always coming blank even service is getting updated.

By looking at your HTML code; I can see both the controllers have already been instantiated.
So when you do $scope.receivedVal = sharedProperties.getString(); in controller 2, you are just getting value from service one time only (Note : You are not continuously observing the value from service). And hence in template of controller 2 the default value firstoccurence shall be displayed.
You are actually updating the value on click of OK button, which in turns updates value in service. But there is no way you told angular that now as values has been changed then now controller 2 should get this new value.
To active the scenario that you want , you need to use $broadcast and $on so that you can continuously observe change happening in controller 1.
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="myCtrl">
<p>Search:<input type="text" ng-model="newValue"></p>
<button ng-click="myFunc(newValue)">OK</button>
</div>
<div ng-controller="myCtrl2">
{{receivedVal}}
<button ng-click="thisWillGetValFromService()" >update this scope's value</button>
</div>
<script>
var app= angular.module('myApp', []);
app.controller('myCtrl', function($rootScope,$scope,sharedProperties) {
$scope.stringValue = sharedProperties.getString();
$scope.myFunc = function(newValue) {
sharedProperties.setString(newValue);
$scope.stringValue = sharedProperties.getString();
console.log($scope.stringValue);
//I am getting the value here by calling sharedProperties.getString();
$rootScope.$broadcast('greeting', newValue);
};
});
app.controller('myCtrl2', function($scope,sharedProperties) {
$scope.receivedVal = sharedProperties.getString();
console.log($scope.receivedVal);
//But I am not getting the updated value here by calling sharedProperties.getString();
$scope.$on('greeting', function(ev,val){
$scope.receivedVal = val
})
});
app.service('sharedProperties', function() {
var stringValue = 'firstoccurence';
return {
getString: function() {
return stringValue;
},
setString: function(value) {
stringValue = value;
},
}
});
</script>
</body>
Above snippet shall solve your problem.
Updated :
Consider a scenario where you have routing configuration defined. So by default only controller 1 and its templates loads in HTML. Then you update ur input box and click OK button. This will save data to service.
Then later on consider on click of some link you re redirecting the app to route of your controller 2 so at this point your controller 2 will get instantiated and $scope.receivedVal = sharedProperties.getString(); this will give you updated value.
Its just a matter of when you load your template (controller) In your case you load both the controllers at a time so you need to use broadcast and on. But if your second component going to load sometime later then you can always use service.

Value is updating in the second controller
But it is not reflecting in the :
<div ng-controller="myCtrl2">
{{receivedVal}}
</div>
Because ng-controller creates new scope
you should write one extra method like in this:
https://codepen.io/amar9312/pen/yRJKGj

Related

Getting the value of ng-model input from controller angular js

I'm trying to get the value of my ng-model input to my controller. The input value has a value and not empty.
Why this code is not working? It says undefined when you alert or console log. What did i missed? really appreciate your help. here is my code
input --> the value is 1
<input type="text" name="idval" ng-model="Data.idval">
js
app.controller('Controller', function($scope, $http){
$scope.fetchvalue = function(){
var id = $scope.Data.idval; // not working
var id = $scope.idval; // even this one
alert(id); // its undefined
$http.post(
"query.php", {
'ID': id,
}
).then(function(response) {
console.log(response.data);
});
}});
Here is a working solution for your code:
You need to declare an object and bind it to ng-model,
$scope.Data = {};
var app = angular.module('myApp', []);
app.controller('formCtrl', function($scope) {
$scope.Data = {};
$scope.fetchvalue = function(){
var id = $scope.Data.idval; // not working
alert(id); // its undefined
}
});
<!DOCTYPE html>
<html lang="en">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="formCtrl">
<form novalidate>
<input type="text" name="idval" ng-model="Data.idval">
<button ng-click="fetchvalue()">Submit</button>
</form>
</div>
</body>
</html>
Here is a working Plunker
I understand,
see you defined id twice, first id get the value from ng-model which must be assigning ng-model value to id variable and you override id with undefined variable called idval.
You can either remove line var id = $scope.idval; or
modify alert(id); as alert($scope.Data.idval)
You need to declare it somewhere before you use it.
$scope.DATA = ""
var id = $scope.Data.idval;
Try this out

AngularJS - two way binding not working using service

I am learning Angular using W3Schools.
I just modified an example about "Services"... The following is the code:
<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<p><input type="text" ng-model="num"></p>
<h2>{{num}}</h2>
<h1>{{hex}}</h1>
</div>
<p>A custom service whith a method that converts a given number into a hexadecimal number.</p>
<script>
var app = angular.module('myApp', []);
app.service('hexafy', function() {
this.myFunc = function (x) {
return x.toString(16);
}
});
app.controller('myCtrl', function($scope, hexafy) {
$scope.num = 200;
$scope.hex = hexafy.myFunc($scope.num);
});
</script>
</body>
</html>
When I update the textbox, the "HEX" part is not updating. Why?
Your hexafy.myFunc is called only once when the controller is initialized, hence only the initial value is converted to hex. If you want a function to be called on the value change of a scope variable in runtime, you need filters. AngularJS has a lot of inbuilt filters that are ready to use.
You can also define a custom filter, just like you define services or controllers.
<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<p><input type="text" ng-model="num"></p>
<h2>{{num}}</h2>
<h1>{{num | hexafy}}</h1>
</div>
<p>A custom filter that converts a given number into a hexadecimal number.</p>
<script>
var app = angular.module('myApp', []);
app.filter('hexafy', function() {
return function (x) {
return Number(x).toString(16); // Also convert the string to number before calling toString.
}
});
app.controller('myCtrl', function($scope) {
$scope.num = 200;
//$scope.hex = hexafy.myFunc($scope.num);
});
</script>
</body>
</html>
Further reading: AngularJS Filters
NOTE: A filter is a good idea if you're gonna be using the hexafy functionality at multiple places in/across views. Otherwise, it is just an overkill and the $scope.$watch method will work fine for you, as described in other answers
$scope.hex is not updating because there're no way for it update itself.
The hexafy.myFunc is called only once when the controller is loaded for the first time.
If you want want the $scope.hex property to change with num, you might need a watch on the num property.
$scope.$watch('num', function(newVal, oldVal) {
$scope.hex = hexafy.myFunc($scope.num); /// or newVal
}
The function passed in $scope.$watch will be called everytime the value of $scope.num changes.
for more info see https://docs.angularjs.org/api/ng/type/$rootScope.Scope (the watch section)
Hope it helps.
No need of a service here, you can simple use $watch on the num. See below code snippet, it will update your ui, I have updated your controller code, please check.
app.controller('myCtrl', function($scope, hexafy) {
$scope.num = 200;
$scope.hex = "some default val";
$scope.$watch('num', function(newValue, oldValue) {
$scope.hex = newValue.toString();
});
});
Your Text box is only bind to 'num'. '$scope.hex is not binded to your text box'. So that it is not update when you typing text. You could use '$watch' on 'num'. Read here
app.controller('myCtrl', function($scope, hexafy) {
$scope.num = 200;
$scope.$watch('num', function() {
$scope.hex = hexafy.myFunc(parseInt($scope.num));
});
});

Angular $scope not getting variables

I have a simple html file that make make search on Algolia and returns result. I can console the result but can not access $scope.users from view. How can I grab that $scope.users in view.
here is my app.js file
var myApp = angular.module('myApp', []);
myApp.controller('usersController', function($scope) {
$scope.users = [];
var client = algoliasearch('my_app_id', 'my_app_key');
var index = client.initIndex('getstarted_actors');
index.search('john', function searchDone(err, content) {
$scope.users.push(content.hits);
console.log(content.hits);
});
});
Here is my html view file
<div class="results" ng-controller="usersController">
<div ng-repeat="user in users">
<h3>{{ user.name }}</h3>
</div>
</div>
note: ng-app="myApp" attribute given in html tag.
It's most likely because your index.search call isn't triggering an Angular $digest cycle - manually trigger one with either $apply or a $timeout
index.search('john', function searchDone(err, content) {
$scope.users.push(content.hits);
$scope.$apply();
});
The $apply() could throw $digest already in progress errors - another way with a $timeout
myApp.controller('usersController', function($scope, $timeout) {
index.search('john', function searchDone(err, content) {
$timeout(function() {
$scope.users.push(content.hits);
});
});
});
try calling $scope.$apply() to update your bindings
index.search('john', function searchDone(err, content) {
$scope.users.push(content.hits);
console.log(content.hits);
$scope.$apply();
});
algoliasearch doesn't look like it's an injected service and therefore not native to the angular framework. Try calling $scope.$apply().

Angular - Template not refreshed with data bound from two different scopes to the same service

I bind data of two different scopes to the same common service data. When I update the data through controller 1, the data in controller 2 is not refreshed in template.
Example showing the issue :
<body ng-app="demoShareBindApp">
<div ng-controller="FirstCtrl as first">
Set share data to : <a href ng-click="setShareDataTo('Me')">"Me"</a>
- <a href ng-click="setShareDataTo('Myself')">"Myself"</a>
- <a href ng-click="setShareDataTo('I')">"and I"</a>
</div>
<div ng-controller="SecondCtrl as second">
Text entered : {{sShareData}}
<br>
<br><a href ng-click="revealShareData()">Reveal data</a>
</div>
<script src="bower_components/angular/angular.js"></script>
<script>
angular
.module('demoShareBindApp', [])
.service('myService', function () {
return {
shareData: null
}
})
.controller('FirstCtrl', ['$scope', 'myService', function ($scope, myService) {
$scope.setShareDataTo = function(content) {
myService.shareData = content;
};
}])
.controller('SecondCtrl', ['$scope', 'myService', function ($scope, myService) {
$scope.sShareData = myService.shareData;
$scope.revealShareData = function() {
console.log(myService.shareData);
}
}]);
</script>
</body>
The Text entered : {{sShareData}} is never updated whereas clicking "Reveal data" shows the right share data in console.
I can't find any clue in other SO post on this particular subject. I guess it could be a matter of "$watch/$digest" but I can't figure out what is really going on here.
Any detailed explanation welcome !
You are sharing data through service. When data in changed under first controller, you set this updated data to service but second controller does not know that shared data referenced by service has changed, so we need to notify the second controller that data has changed or we can shared data through events
I created a fiddle, check it
https://jsbin.com/midebu/edit?html,js,output
First approach. Using service
$scope.setShareDataTo = function(content) {
myService.shareData = content;
$rootScope.$broadcast('datacChanged');
};
In second cntroller
$rootScope.$on('dataChanged', function(){
// get updated data
$scope.sShareData = myService.shareData;
})
Other way is that, we do not need to use service , we can simply pass that shared data using events
$scope.setShareDataTo = function(content) {
$rootScope.$broadcast('datacChanged', content);
};
And in Second controller
$rootScope.$on('dataChanged', function(event, data){
// get updated data
$scope.shareData = data;
})

update angularjs model from jquery [duplicate]

I have this simple scenario:
Input element which value is changed by jQuery's val() method.
I am trying to update the angular model with the value that jQuery set. I tried to write a simple directive, but it's not doing what I want.
Here's the directive:
var myApp = angular.module('myApp', []);
myApp.directive('testChange', function() {
return function(scope, element, attrs) {
element.bind('change', function() {
console.log('value changed');
})
}
})
this is the jQuery part:
$(function(){
$('button').click(function(){
$('input').val('xxx');
})
})
and html:
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<input test-change ng-model="foo" />
<span>{{foo}}</span>
</div>
</div>
<button>clickme</button>
Here is the fiddle with my try:
http://jsfiddle.net/U3pVM/743/
Can someone please point me in the right direction?
ngModel listens for "input" event, so to "fix" your code you'd need to trigger that event after setting the value:
$('button').click(function(){
var input = $('input');
input.val('xxx');
input.trigger('input'); // Use for Chrome/Firefox/Edge
input.trigger('change'); // Use for Chrome/Firefox/Edge + IE11
});
For the explanation of this particular behaviour check out this answer that I gave a while ago: "How does AngularJS internally catch events like 'onclick', 'onchange'?"
But unfortunately, this is not the only problem you have. As pointed out with other post comments, your jQuery-centric approach is plain wrong. For more info take a look at this post: How do I “think in AngularJS” if I have a jQuery background?).
Hope this is useful for someone.
I was unable to get the jQuery('#myInputElement').trigger('input') event to be picked up my angular app.
I was however, able to get angular.element(jQuery('#myInputElement')).triggerHandler('input') to be picked up.
The accepted answer which was triggering input event with jQuery didn't work for me. Creating an event and dispatching with native JavaScript did the trick.
$("input")[0].dispatchEvent(new Event("input", { bubbles: true }));
I don't think jQuery is required here.
You can use $watch and ng-click instead
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<input test-change ng-model="foo" />
<span>{{foo}}</span>
<button ng-click=" foo= 'xxx' ">click me</button>
<!-- this changes foo value, you can also call a function from your controller -->
</div>
</div>
In your controller :
$scope.$watch('foo', function(newValue, oldValue) {
console.log(newValue);
console.log(oldValue);
});
You have to use the following code in order to update the scope of the specific input model as follows
$('button').on('click', function(){
var newVal = $(this).data('val');
$('select').val(newVal).change();
var scope = angular.element($("select")).scope();
scope.$apply(function(){
scope.selectValue = newVal;
});
});
I made modifications on only controller initialization by adding listener on action button:
$(document).on('click', '#action-button', function () {
$timeout(function () {
angular.element($('#input')).triggerHandler('input');
});
});
Other solutions did not work in my case.
I know it's a bit late to answer here but maybe I may save some once's day.
I have been dealing with the same problem. A model will not populate once you update the value of input from jQuery. I tried using trigger events but no result.
Here is what I did that may save your day.
Declare a variable within your script tag in HTML.
Like:
<script>
var inputValue="";
// update that variable using your jQuery function with appropriate value, you want...
</script>
Once you did that by using below service of angular.
$window
Now below getData function called from the same controller scope will give you the value you want.
var myApp = angular.module('myApp', []);
app.controller('imageManagerCtrl',['$scope','$window',function($scope,$window) {
$scope.getData = function () {
console.log("Window value " + $window.inputValue);
}}]);
I've written this little plugin for jQuery which will make all calls to .val(value) update the angular element if present:
(function($, ng) {
'use strict';
var $val = $.fn.val; // save original jQuery function
// override jQuery function
$.fn.val = function (value) {
// if getter, just return original
if (!arguments.length) {
return $val.call(this);
}
// get result of original function
var result = $val.call(this, value);
// trigger angular input (this[0] is the DOM object)
ng.element(this[0]).triggerHandler('input');
// return the original result
return result;
}
})(window.jQuery, window.angular);
Just pop this script in after jQuery and angular.js and val(value) updates should now play nice.
Minified version:
!function(n,t){"use strict";var r=n.fn.val;n.fn.val=function(n){if(!arguments.length)return r.call(this);var e=r.call(this,n);return t.element(this[0]).triggerHandler("input"),e}}(window.jQuery,window.angular);
Example:
// the function
(function($, ng) {
'use strict';
var $val = $.fn.val;
$.fn.val = function (value) {
if (!arguments.length) {
return $val.call(this);
}
var result = $val.call(this, value);
ng.element(this[0]).triggerHandler('input');
return result;
}
})(window.jQuery, window.angular);
(function(ng){
ng.module('example', [])
.controller('ExampleController', function($scope) {
$scope.output = "output";
$scope.change = function() {
$scope.output = "" + $scope.input;
}
});
})(window.angular);
(function($){
$(function() {
var button = $('#button');
if (button.length)
console.log('hello, button');
button.click(function() {
var input = $('#input');
var value = parseInt(input.val());
value = isNaN(value) ? 0 : value;
input.val(value + 1);
});
});
})(window.jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div ng-app="example" ng-controller="ExampleController">
<input type="number" id="input" ng-model="input" ng-change="change()" />
<span>{{output}}</span>
<button id="button">+</button>
</div>
If you are using IE, you have to use: input.trigger("change");
add .change() after setting the value.
example:('id').val.('value').change();
also don't forget to add onchange or ng-change tag in html
I did this to be able to update the value of ngModel from the outside with Vanilla/jQuery:
function getScope(fieldElement) {
var $scope = angular.element(fieldElement).scope();
var nameScope;
var name = fieldElement.getAttribute('name');
if($scope) {
if($scope.form) {
nameScope = $scope.form[name];
} else if($scope[name]) {
nameScope = $scope[name];
}
}
return nameScope;
}
function setScopeValue(fieldElement, newValue) {
var $scope = getScope(fieldElement);
if($scope) {
$scope.$setViewValue(newValue);
$scope.$validate();
$scope.$render();
}
}
setScopeValue(document.getElementById("fieldId"), "new value");
Not what OP asked, but for any soul that might be as well writing an userscript that goes through input fields and fills the required details. Nothing (fully) worked for me, but finally managed to get it done this way:
var el = $('#sp_formfield_fw_ip');
el.val("some value");
angular.element(el).triggerHandler('focus');
angular.element(el).triggerHandler('input');
angular.element(el).triggerHandler('change');
angular.element(el).triggerHandler('blur');
Open developer tools, and inspect input field for added events. There I found all of them (in my case): focus, input, change and blur.

Resources