how to access to a $scope value into a controller - angularjs

can someone explain me why i cannot get the $scope.pk value in my console.log()
'use strict';
angular.module('angularDjangoRegistrationAuthApp')
.controller('TweatCtrl', function ($scope, $location, djangoAuth, djangoTweat, $routeParams) {
$scope.tweek = function(){
console.log(' tweek ');
};
djangoAuth.profile().then(function(data){
$scope.user = data;
$scope.pk = data.pk;
});
djangoTweat.getUserTweeks(1)
.then(function(data){
$scope.tweeks = data
},function(data){
// error case
$scope.errors = 'no tweeks';
});
console.log($scope);
console.log($scope.pk);
The fisrt console.log() returns me the Scope object with a pk value.
The second console.log() returns 'undefined' :(

You are trying to access $scope.$pk before it is set.
The following code is probably run asynchronously, as it is using promises. It will run some time after the console.log statements at the end of your controller initialization. It will only run if the djangoAuth.profile() promise is resolved (succeeds).
djangoAuth.profile().then(function(data){
$scope.user = data;
$scope.$pk = data.pk;
// now log $scope.$pk after it is set (assuming data.pk is not undefined)
console.log("$scope.$pk is", $scope.$pk, "and data.pk is", data.pk);
});

i saw a declaration of $pk, your're trying to log a pk attr of $scope..
Console.log($scope.$pk); //it should be ok..
Another thing, i suggest you to use $log, and include it in the function of the controller, then, you'll be able to use $log.Error, $log.Debug and $log.log to the standard console..

Related

Make data from factory http.get accessible to entire controller AngularJS

I am trying to give access to a json file that contains config information for my project (things like rev number, project name, primary contact, etc) I created a factory that retrieves the json file using http.get, I can then pull that data into my controller but I am unable to access it from anywhere in the controller.
I did not write the factory, I found it as an answer to another person's question and it is copied almost entirely so if it not the right way to accomplish what I am trying to do please correct me.
here is the factory:
app.factory('configFactory', ["$http", function($http) {
var configFactory = {
async: function() {
// $http returns a promise, which has a then function, which also returns a promise
var promise = $http.get('assets/json/config.json').then(function(response) {
// The then function here is an opportunity to modify the response
console.log(response.data.config);
// The return value gets picked up by the then in the controller.
return response.data.config;
});
// Return the promise to the controller
return promise;
}
};
return configFactory;
}]);
and here is my controller:
app.controller('footerController', ['$scope', '$rootScope', 'configFactory', function footerController($scope, $rootScope, configFactory) {
var body = angular.element(window.document.body);
$scope.onChange = function(state) {
body.toggleClass('light');
};
configFactory.async().then(function(d) {
$scope.data = d;
// this console log prints out the data that I am trying to access
console.log($scope.data);
});
// this one prints out undefined
console.log($scope.data);
}]);
So essentially I have access to the data within the function used to retrieve it but not outside of that. I can solve this with rootScope but I am trying to avoid that because I think its a bandaid and not a proper solution.
Any help would be great but this is my first experience with http.get and promises and all that stuff so a detailed explanation would be very much appreciated.
[EDIT 1] The variables from the config file will need to be manipulated within the web app, so I can't use constants.
Don't assign your response data to scope variable , create a property in your factory itself and assign the response to this property in your controller when your promise gets resolved.This way you will get the value in all the other controllers.
I have updated your factory and controller like below
app.factory('configFactory', ["$http", function($http) {
var configFactory = {
async: function() {
// $http returns a promise, which has a then function, which also returns a promise
var promise = $http.get('assets/json/config.json').then(function(response) {
// The then function here is an opportunity to modify the response
console.log(response.data.config);
// The return value gets picked up by the then in the controller.
return response.data.config;
});
// Return the promise to the controller
return promise;
},
config:'' // new proprety added
};
return configFactory;
}]);
app.controller('footerController', ['$scope', '$rootScope', 'configFactory', function footerController($scope, $rootScope, configFactory) {
var body = angular.element(window.document.body);
$scope.onChange = function(state) {
body.toggleClass('light');
};
configFactory.async().then(function(d) {
// $scope.data = d;
configFactory.config=d;
// this console log prints out the data that I am trying to access
console.log($scope.data);
});
// this one prints out undefined
console.log($scope.data);
}]);
Have you looked into using angular constants? http://ilikekillnerds.com/2014/11/constants-values-global-variables-in-angularjs-the-right-way/ You can leverage them as global variables accessible from any controller without the ramifications of assigning the values to rootScope

How can I create a service that returns the value promise

I want to create a service that returns a json
Or by request to to the server, or by checking if it exists already in: Window.content
But I don't want to get a promise from my Controller !
I want to get the json ready !
I have tried several times in several ways
I tried to use with then method to do the test in my Service
but I still get a promise
( Whether with $http only, and whether with $q )
I could not get the value without getting promise from my Controller
My Service :
app.service('getContent',['$http', function( $http ){
return function(url){ // Getting utl
if(window.content){ // if it's the first loading, then there is a content here
var temp = window.content;
window.content = undefined;
return temp;
}
return $http.get(url);
};
}]);
My Controller:
.state('pages', {
url: '/:page',
templateProvider:['$templateRequest',
function($templateRequest){
return $templateRequest(BASE_URL + 'assets/angularTemplates/pages.html');
}],
controller: function($scope, $stateParams, getContent){
// Here I want to to get a json ready :
$scope.contentPage = getContent(BASE_URL + $stateParams.page + '?angular=pageName');
}
});
If the data exists, just resolve it in a promise.
While this process is still asynchronous it won't require a network call and returns quickly.
app.service('getContent',['$http', '$q', function( $http, $q ){
return function(url){
// create a deferred
var deferred = $q.defer();
if(window.content){ // if it's the first loading, then there is a content here
var temp = window.content;
window.content = undefined;
deferred.resolve(temp); // resolve the data
return deferred.promise; // return a promise
}
// if not, make a network call
return $http.get(url);
};
}]);
Just to reiterate, this asynchronous, but it won't require a network call.
This is not possible. If the code responsible to calculate or retrieve the value relies on a promise, you will not be able to return the value extracted from the promise by your function.
Explanation: This can easily be seen from the control flow. A promise is evaluated asynchronously. It may take several seconds to retrieve json from a server, but the caller of your function should not wait so long because your whole runtime environment would block. This is why you use promises in the first place. Promises are just a nice way to organize callbacks. So when your promise returns, the event that caused the function call will have already terminated. In fact it must have, otherwise your promise could not be evaluated.
You're thinking about this wrong. A service always returns a promise, because there is no synchronous way of getting JSON from an API:
app.factory('myService', ['$http', function($http) {
return $http('http://my_api.com/json', function(resp) {
return resp.data;
});
}]);
You would then call this within your controller like so:
app.controller('myController', ['$scope', 'myService', function($scope, myService) {
myService.then(function(data) {
$scope.contentPage = data; // here is your JSON
}, function(error) {
// Handle errors
});
}]);
Your service is returning a promise as it's written at the moment. A promise is always a promise, because you don't really know when it will be finished. However with Angular's 2 way data binding this isn't an issue. See my edits bellow as well as the example on $HTTP in the docs
In your controller
controller: function($scope, $stateParams, getContent){
getContent(BASE_URL + $stateParams.page + '?angular=pageName')
.then(aSuccessFn, aFailedFn);
function aSuccessFn(response) {
// work with data object, if the need to be accessed in your template, set you scope in the aSuccessFn.
$scope.contentPage = response.data;
}
function aFailedFn(data) {
// foo bar error handling.
}
}

AngularJS extend Controller within controller

here's my issue: I want to run the code of controllerB into controllerA. The issue is that while the variables are returned to the controllerA, the values from requests are never returned. Here's a plunker to show the issue: http://plnkr.co/edit/GqC9BOKTi8HxQLf2a2yd?p=preview
var test = $scope.$new();
$controller('Ctrl1', {$scope : test});
//the first 2 lines are executed, but the 3d never returns a value
$scope.variable = test.variable;
$scope.varFromFunction = test.varFromFunction();
$scope.varFromRequest = test.varFromRequest;
The first 2 lines execute, but the 3d one never returns a value.
Since varFromRequest is located inside a $timeout method in the first controller with 500ms, it will execute 500s later meanwhile angular completes its linking phase.
Watching varFromRequest in the second controller is the easy solution
test.$watch('varFromRequest', function(new_value, old){
$scope.varFromRequest = test.varFromRequest;
})
Here is the updated plunker http://plnkr.co/edit/TqSjeckrdqeKquEbCwFX
The varFromFunction is undefined when the second controller tries to get a reference. The timeout sets this var after this request. If you delay the request for reference then you will get the appropriate value. This isn't the recommended way of working but it does answer your question why it hasn't been set yet.
myApp.controller('Ctrl1', ['$scope', '$timeout', function($scope, $timeout) {
$scope.variable = 'OH HAI';
$scope.varFromFunction = function(){
return "OH HAI FromFunction";
}
$timeout(function(){
$scope.varFromRequest = "time";
},500);
}]);
myApp.controller('Ctrl2', ['$scope', '$controller', '$timeout', function($scope, $controller, $timeout) {
var test = $scope.$new();
$controller('Ctrl1', {$scope : test});
$scope.variable = test.variable;
$scope.varFromFunction = test.varFromFunction();
$scope.varFromRequest = test.varFromRequest || 'unset';
$timeout(function(){
$scope.varFromRequest = test.varFromRequest || 'still unset';
},500);
}]);

AngularJS - $scope undefined within same controller

I have a controller where I am trying to store information in $scope.weather and then use it's contents to pass to a function. When I log the result of $scope.weather[0].latitude when I use it one function but when I call it another function within the same controller the result is coming back undefined. Shouldn't the $scope be usable within the same controller? This is also within the same function.
angular.module('CityCtrl', []).controller('CityController', ['$scope', '$http', 'City', function($scope, $http, City){
$scope.update = function (zip) {
City.get({zip : zip}).success(function(response){
$scope.weather = response
}).then(function(response){
$scope.weather = response.data;
// This is returning the expected result
console.log($scope.weather[0].latitude;
})
if(zip.length === 5){
// This is coming back undefined
console.log($scope.weather[0].latitude);
var box = getBoundingBox([$scope.weather[0].latitude, $scope.weather[0].longitude], 50);
City.matches(box[1], box[3], box[0], box[2]).success(function(response){
$scope.matches = response
}).then(function(response){
$scope.matches = response.data;
console.log($scope.matches);
})
}
}
}]);
This is an order of operations issue.
When you console.log($scope.weather[0].latitude) in the if statement $scope.weather has not actually been set yet because the City.get() call is asynchronous. This means $scope.weather will not be set until a successful response is returned from the City service, which in your case will execute after the code block in the if statement.
In order for your if statement code to have access to $scope.weather you would need to include it in the .then(function() { // if logic here } portion of your code.
Also it is worth noting that City.get().success() and City.get().then(successFunction) are pretty much doing the same thing. You should use one or the other, but you shouldn't need to use both.

how to handle firebase's asynchronous snapshot.val() function

From what I understand, Firebase's snapshot.val() function is asynchronous, but I am not sure how to handle/change my code to account for this situation.
In short, this is the code of my controller:
.controller('MyController', ['$firebase', '$scope', 'authService', 'rootRef', function(authService, $firebase, $scope, rootRef) {
var auth = authService.getCurrentUser();
$scope.data = [];
if (auth) {
rootRef.on('child_added', function(snapshot) {
console.log(snapshot.val());
$scope.data.push(snapshot.val());
console.log($scope.data);
})
};
From this code, what I see in the console is this:
output of snapshot.val()
output of $scope.data
However, the code in between console.log(snapshot.val()) and console.log($scope.data) does NOT seem to run because my $scope.data variable does not get updated!
Can someone please explain this behavior?
I think it has to do with the fact that snapshot.val() is asynchronous. But more importantly, can someone explain how I can easily resolve this issue instead of doing what I figured out below.
My solution:
I figured out one way to make it work, which is VERY roundabout. What I do is I take snapshot.name(), which gives me the $id or key for this object. I then make a .$asObject().$loaded() call to the location with that $id (essentially getting a promise to read that precise object). Then, in the success callback, I update $scope.data.
You defined an array called "data" on scope:
$scope.data = [];
But you are pushing to a variable called "testing" in your onComplete callback
$scope.testing.push(snapshot.val());

Resources