Angular Service data not updating in $scope - javascript

I am not able to update data in my controller using the service. I want to do an http.get in my service, do some processing on the data and then update the $scope of the controller.
I have an angular service like below. From the answers I have read in the forums my data should be updating in the view. But thats not happening.
app.service('myService', function($http, $rootScope) {
this.selected = {
item: ''
}
this.getData = function(key){
return $http.get('/myapp/stocklist/'+key);
}
this.gs = [];
this.sr = [];
this.siri=[];
var vm=this;
this.cleanData = function(response){
for( var i=0; i<response.data.length; i++ ) {
vm.gs.push(response.data[i].name);
vm.sr.push(response.data[i].high);
}
vm.siri.push(vm.sr);
}
});
and here is the controller. The gs and sr variable are blanks. From what I read I dont need to use watch for this and the code below should work(I am not very clear on how to use watch as well). If this would work with watch can you please tell me how to do it.
app.controller('graph', ['$scope', '$http', 'myService', function($scope,$http, myService) {
$scope.mySelected = myService.selected;
console.log($scope.mySelected);
myService.getData($scope.mySelected).then(function(response){
myService.cleanData(response);
$scope.sr=myService.siri;
$scope.gs=myService.gs;
console.log(myService.sr);
});
}]);
I am new to angular and also maybe structuring the code in the wrong way. I would appreciate any design suggestions as well.
I am also wondering if I am using service in the right way for $http.get. I had asked a question earlier in the forum and this is what I had got as a reply. It works when I use the returned data from the service function and do data processing in the controller itself.
Can you please help?

Looks like you're calling the myService service again to set the sr $scope after getting a response. Instead, set $scope.sr and $scope.gs to response.siri and response.gs, respectively. Updated code below:
app.controller('graph', ['$scope', '$http', 'myService', function($scope,$http, myService) {
$scope.mySelected = myService.selected;
console.log($scope.mySelected);
myService.getData($scope.mySelected).then(function(response){
$scope.cleanData = response;
$scope.sr = response.siri;
$scope.gs = response.gs;
console.log($scope.sr);
});
}]);

Sorry this works fine. I made a mistake in making the get call. Hence not giving the correct data. Thank you for your help :)

Related

[JavaScript][Angular]: TypeError: Cannot read property 'getCityData' of undefined

This question has been asked many times before and I've tried the answers but they do not seem to solve the problem I'm facing. I'm new to Angular and am trying to pass a value from the controller to a factory so that I can retrieve some JSON information through an API. While I'm able to get the value from my HTML to the controller, the next step is giving me a TypeError: Cannot read property 'getCityData' of undefined. My controller code is as follows:
app.controller('MainController', ['$scope', function($scope, HttpGetter) {
var successFunction = function(data) {
$scope.data = data;
}
var errorFunction = function(data) {
console.log("Something went wrong: " + data);
}
$scope.cityName = '';
$scope.getCityName = function(city) {
$scope.cityName = city;
HttpGetter.getCityData($scope.cityName, successFunction, errorFunction);
};
}]);
The factory code is as follows:
app.factory('HttpGetter', ['$http', function($http){
return {
getCityData: function(query, successFunction, errorFunction){
return $http.get('http://api.apixu.com/v1/current.json?key=MyAppKey&q=' + query).
success(successFunction).
error(errorFunction);
}
};
}]);
I've replaced my App key with the string "MyAppKey" just to be safe but my code contains the appropriate key. Also, it would be very helpful if I could get a bit of an insight on how the function invocations happen because there seem to be a lot of function callbacks happening.
Getting undefined could be because of the service not getting properly injected.
Try:
app.controller('MainController', ['$scope', 'HttpGetter', function($scope, HttpGetter)
Also as you said, to be on safer side you aren't using the right key, but anyone using your application can get the key by checking the network calls. So, ideally, one should make a call to the backend, and backend will send a call along with the secured key to the desired API endpoint and return the response data to front-end.
Can be due to ['$scope', function($scope, HttpGetter) ?
Should be ['$scope', 'HttpGetter', function($scope, HttpGetter) instead.
You used minified version and inject only $scope not HttpGetter but used as argument in controller function that's why got HttpGetter is undefiend and error shown Cannot read property 'getCityData' of undefined
So you should inject HttpGetter in your minified version ['$scope', 'HttpGetter'
use like:
app.controller('MainController', ['$scope', 'HttpGetter', function($scope, HttpGetter)
instead of
app.controller('MainController', ['$scope', function($scope, HttpGetter)
And if your MyAppKey is secured and want to hide from user then you should use it in server side

Not able to access the $scope value in html, value set in $http.post success function

I am not able to access the value of the $scope properties set on success of $http post. I am trying to access it in index.html file. below is the code for reference, please help me in resolving it, i am new to AngularJs
var app = angular.module('formExample', []);
app.controller("formCtrl", ['$scope','$rootScope', '$http',
function($scope,$rootScope, $http) {
$scope.loginurl = 'loginsubmit.php';
$scope.loginFormSubmit = function(isValid) {
if (isValid) {
$http.post($scope.loginurl, {"username": $scope.username,"password": $scope.password}).
success(function(data, status) {
$scope.status = status;
$scope.data = data;
$scope.isAdmin=data.isAdmin;
$scope.username=data.username;
location.href="Index.html";
})
}else{
alert('Form is not valid');
}
}
html form code
<div class="row" ng-app="formExample" >
<div ng-controller="formCtrl">
<div class"col-md-8"> </div>
<div>username: {{$scope.username}} </div>
For login and authentication I usually do the same thing Marco does (mentioned in his comment) and store in $rootScope the user information. However, that is essentially the only thing I ever use it for as it is best to avoiding polluting the rootScope with a bunch of stuff.
I set up a small playground in a jsfiddle for you shamelessly stolen from this article:
http://www.dotnet-tricks.com/Tutorial/angularjs/UVDE100914-Understanding-AngularJS-$rootScope-and-$scope.html
http://jsfiddle.net/chrislewispac/kd8v6thm/
var app = angular.module('myApp', []);
app.controller('Ctrl1', function ($scope, $rootScope) {
$scope.msg = 'World';
$rootScope.name = 'AngularJS';
});
app.controller('Ctrl2', function ($scope, $rootScope) {
$scope.msg = 'Dot Net Tricks';
$scope.myName = $rootScope.name;
});
All other answers/comments are great. I just wanted you to have this fiddle to play around with. I have learned a lot by isolating small issues and testing them, breaking them, and fixing them in fiddles.
EDIT: There are ways to share data across controllers in Angular:
Also, to address other ways to share data between controllers without a database you can also create an auth 'factory.' Services and Factories are great ways to share data across controllers and I believe they are the actual intended way.
A good discussion of this option (and others) is here:
https://medium.com/opinionated-angularjs/techniques-for-authentication-in-angularjs-applications-7bbf0346acec
See updated fiddle with example of a service:
http://jsfiddle.net/chrislewispac/kd8v6thm/1/
with the following added:
app.service("auth", [ function () {
return {
getAuth: function () {
var info = {
name: "Name",
password: "Password"
}
return info;
}
};
}]);
You may want to timeout your location.href so that the $scope is not lost.
Before the redirect, you have several options to make your user data global to the app. You can put your user variables in a controller that affects all views (such as a controller in app.js), or put it in $rootScope or localStorage/sessionStorage as #Marco in the comments suggests.
Also, use {{ username }} instead of {{ $scope.username }}. The latter doesn't print anything.

AngularJs local variable weird behavior

This is the code in the controller
cat1=[];
$.getJSON('categories/1/', function(data) {
cat1 = data; //returns a JSON
});
//cat2..4 are some JSONs
$scope.pictures=[cat1,cat2,cat3,cat4,cat5];
The problem is that seems like cat1=[] and cat1=data are different variables, cause pictures[cat1] always returns []
Am I doing it wrong?
Because $.getJSON is an async request and is still processing when you try and log. Also, don't use jQuery with Angular, use Angular's $http (this way a $digest cycle is triggered and everything stays in sync):
$http.get("categories/1/").success(function(data) {
cat1 = data; //returns a JSON
$scope.pictures=[cat1,cat2,cat3,cat4,cat5];
});
Dont forget to add $http as a dependency in your controller:
app.controller("myCtrl", ["$scope", "$http", function($scope, $http) {
}]);

What is the best way to let other sibling controller's know of changes in angularjs?

I've been thinking about this topic for a while and I've seen most of the threads pertaining to communication between controllers. It's simple to share data between controllers, I built out this simple fiddle to demonstrate what I've managed to understand so far.
JS fiddle link - http://jsfiddle.net/fb3qyuat/2/
Code Snippet
var myApp = angular.module('myApp',[]);
myApp.controller('Ctrl1', ['$scope', 'shareData', function($scope, shareData) {
$scope.person = {
name: 'Joe',
age: '35',
occupation: 'Pizza Chain Owner'
};
$scope.changeData = function(data) {
shareData.setData(data);
};
$scope.getData = function(data) {
$scope.person = shareData.getData();
};
}]);
myApp.controller('Ctrl2', ['$scope', 'shareData', function($scope, shareData) {
$scope.person = {
name: 'Dr Dre',
age: '30',
occupation: 'Rapper'
};
$scope.changeData = function(data) {
shareData.setData(data);
};
$scope.getData = function(data) {
$scope.person = shareData.getData();
};
}]);
myApp.controller('Ctrl3', ['$scope', 'shareData', function($scope, shareData) {
$scope.changeData = function(data) {
shareData.setData(data);
};
$scope.getData = function(data) {
$scope.person = shareData.getData();
};
}]);
myApp.factory('shareData', function() {
var shareData = {};
shareData.setData = function(dataEntered) {
shareData = dataEntered;
};
shareData.getData = function() {
return shareData;
};
return shareData;
});
Where I get confused is what is the best way to notify other controllers that rely on this new and updated data. I know some ways of doing this but a developer friend of mine is very against GOTO events ($broadcast, $on, $emit).
Is there any other way of notifying a particular controller about a change in data when another controller updates the data?
Follow up question: If event based notification is really the only legitimate option where is the best place to handle the $broadcast or $emit. Inside of the service using the $rootscope (sounds like a no-no) or inside the controller after updating the data.
One option is to make a service that stores and exposes the shared data. Then, take a dependency on the service in each controller. Setup a watch in your controller that watches the value of the shared data on the service. The watch will fire any time the data in the service changes. Just be careful to avoid creating an event cycle.
Technically, you don't even need a service. You just need a place that stores shared data, which it looks like you have. For your example, you could just put a $watch on getData(), like so:
http://jsbin.com/qezoyevuqiko/1/
Just be aware of the downfalls of using watches. They can be expensive if your watch evalation function is slow. In that case, maybe you store with the data a hash code or some sort of flag that makes evaluating if a change has been made more efficient.
I appreciate the solution John but I think I have found a better way that doesn't use watch or any other event GOTOs. Here it is in this jsfiddle. http://jsfiddle.net/ge9esec4/
It was actually much easier than I thought. Essentially a factory would hold your object like we did before but instead of creating the obj inside the controller, it is created inside the factory and then injected into the controllers via DI. Once inside the controllers you can manipulate the data however you please and they will essentially be a reference to the original which is inside the factory. I think this is a much more efficient solution.

JSON parsing error in angularjs when getting from server but not when static

I have this plunker:
http://plnkr.co/edit/FnCTfZf8RVBx2WVscyK8?p=info
if I change the line/s(around 23)
app.controller('MainCtrl', function($scope) {
$scope.links = [...];
});
to
app.controller('MainCtrl', function ($scope, $http) {
$http.get('data.json')
.success(function(data, status, headers, config) {
$scope.links = data;
});
I don't see any data.
I guess this happens because the data is set after the ui has already been rendered.
How do I make the data binding work corectlly?
Thanks
The issue you are facing is different reference of variables.
i.e when you say
a = b
Then when you modify "b", "a" is not going to change. Hence, in ng-init you have just initialized with value
submenu = links
When "links" gets updated then "submenu" does not.
So, here you can setup watch on scope variable "links", which when updated you can update "submenu".
Please find the plunkr for the same.
Code:
$scope.$watch('links',function(newValue){
$scope.submenu=newValue;
});

Categories

Resources