Angular and MEAN.js $scope attributes are undefined - angularjs

I am currently developing a little app with Angular and MEAN.js.
I would like to plot a D3 chart with some real data coming from the model.
To do so, I would have to read from the $scope.campaign variable and initialize the $scope.dataBarChart with the data from $scope.campaign.tokens that is an array.
// Find existing Campaign
$scope.findOne = function() {
$scope.campaign = Campaigns.get({
campaignId: $stateParams.campaignId
});
$scope.dataBarChart = [
{
'key': 'Token Requested',
'values': [['10.10.2014', 550000], ['11.10.2014',300000]]
}, {
'key': 'Token Consumed',
'values': [['10.10.2014', 250000], ['11.10.2014',200000]]
}
];
};
When I try to log the value of $scope.campaign, I get all the data that I need. Unfortunately, when I try to access the $scope.campaign.tokens, I get an error like impossible to access tokens from undefined value. Basically, it seems that there is no data, but I know from the log that is not like this.
The complete code is simply the same, but with a console.log line
// Find existing Campaign
$scope.findOne = function() {
$scope.campaign = Campaigns.get({
campaignId: $stateParams.campaignId
});
console.log($scope.campaign)
$scope.dataBarChart = [{
'key': 'Token Requested',
'values': [['10.10.2014', 550000], ['11.10.2014',300000]]
}, {
'key': 'Token Consumed',
'values': [['10.10.2014', 250000], ['11.10.2014',200000]]
}];
};
The console.log shows the right content, but when I try to use it $scope.campaign.tokens, it says undefined.
Anyone suggestions?
Thanks

Try
$scope.campaign.$promise.then(function(data) {
console.log(data.tokens)
});

Related

AngularJs - keeps getting old value of scope even if it is updated

In my application, I'm retrieving some fields from the database and setting the values in local storage when a user logs in.
and then retrieving from local storage to display it to user:
if (localStorage.getItem('a') != undefined) {
$rootScope.a = localStorage.getItem('a');
}
So this is working fine. But the problem is when the value gets updated in the database and user logs in after logging out, then even if the local storage has correct value (i.e., recently updated value), the first time it will display the old value of the scope variable which just got updated.
I tried $apply() and also $digest() as suggested in different posts here :
$timeout( function () {
$scope.$apply( function () {
$rootScope.a = localStorage.getItem('a');
});
});
But it didn't work out. It always displays the old value of scope.
It will only display the new value after reloading the page once.
P.S. - The web page in my application won't be reloaded in any module, even when logging in and out.
You can try watching for the scope variable like this:
$rootScope.$watch('a', function (newVal, oldVal){
if newVal != oldVal
$rootScope.a = newVal;
}
Something else to try is to change 'a' from string to object as I think that angular watches for values using object reference.
here's some useful reference for $watch
http://www.learn-angular.org/#!/lessons/watch
https://www.bennadel.com/blog/2852-understanding-how-to-use-scope-watch-with-controller-as-in-angularjs.htm
Hope it helps in any way
EDIT
ok I tested it. You don't need watch neither $apply if you refresh the scope when data refreshing.
Here's what I've done:
(function() {
angular.module('myapp', []).controller('myctrl', [
'$scope', function($scope) {
var data, getDataFromLocalStorage;
console.log("scope is ", $scope);
getDataFromLocalStorage = function() {
return JSON.parse(localStorage.getItem('data'));
};
data = [
{
id: 1,
text: "test1"
}, {
id: 2,
text: "test2"
}, {
id: 3,
text: "test3"
}
];
localStorage.setItem('data', JSON.stringify(data));
$scope.myData = getDataFromLocalStorage();
return $scope.changeData = function() {
var dataNew;
dataNew = [
{
id: 4,
text: 'text4'
}, {
id: 5,
text: 'text5'
}, {
id: 6,
text: 'text6'
}
];
localStorage.setItem('data', JSON.stringify(dataNew));
return $scope.myData = getDataFromLocalStorage();
};
}
]);
}).call(this);
https://codepen.io/NickHG/pen/rzvGGx?editors=1010

How to avoid adding to many watchers on same object

Currently I'm getting a pretty messy response from the server, and If store everything in one Object and then bind that as model on formly-form I have huge lag on when typing something to text input.It's caused because there are 3 arrays with over 850 items and as I understand Angular Formly observe those things too.
So I decided to split data in 2 objects
One that holds everything and It's not binded as model to formly-form
Other that holds initial data which are pretty light, and those things are binded to the formly-form model.
Here is the skeleton:
$scope.allData = {}
$scope.formlyData = {}
$scope.initData = function() {
myService.get()
.then(function(response) {
$scope.allData = response.data
$scope.formlyData['important'] = response.data.important
})
}
Remember huge arrays ? Well basically they should be stored in select inputs, and with formly I tried to make It like this:
var vm = $scope
$scope.formFields = [{
fieldGroup: [
{
'key': 'actors',
'type': 'select',
'className': 'col-sm-6',
'templateOptions': {
options: []
},
controller: function($scope) {
$scope.to.options = vm.allData.actors
}
}
]
}]
And this doesn't work because allData is empty when It's executed and It's populated later because of $http call which is async.
Okay I tried to use watcher:
var vm = $scope;
$scope.formFields = [
fieldGroup: [
{
'key': 'actors',
'type': 'select',
'className': 'col-sm-6',
'templateOptions': {
options: []
},
controller: function($scope) {
vm.$watch('allData', function(newVal) {
$scope.to.options = newVal.actors
})
}
}
]
]
But something is not good and loading takes a quite long (response is fetched for 200ms).Is It because I have about 10 fields with same behaviour and then there is a many watchers on same object ?
Any better idea to handle this, or sort of improvment ? Thanks.

Why is Angular http.post converting string value to an array?

I have an Angular JS and Laravel app. One of my form feilds is an ng-options driven select. The values are strings but when I post using http.post, one of the values seems to be getting converted to an array.
I have this in my JS controller for the options;
$scope.periods = [
{label: '1'},
{label: '2'},
{label: '3'},
{label: 'OT'}
];
This is my view for the select;
<select ng-model="egoal.period"
ng-options="period.label as period.label for period in periods"
class="form-control game-control"
required>
</select>
And then this in the controller to post;
$scope.changeGoal = function() {
var egoal = this.egoal;
$http.post('api/editGoal/' + this.goal.id, egoal)
.success(function () {
$scope.egoal = {};
});
};
Oddly, when I dump the $request, I get period => [] and then this error;
ErrorException in helpers.php line 685:
preg_replace(): Parameter mismatch, pattern is a string while replacement is an array
Been looking at this for a long time now. What could be causing this?
Thanks!
UPDATE:
Egoal object looks like this after the selection is made;
EGoal: {
"id": 268,
"game": 147,
"season": 4,
"team_id": 2,
"period": "2",
"min": 7,
"sec": 54,
"scorer": 11,
}
but the period value is converted on post to an empty array...
$scope.changeGoal = function() {
var egoal = this.egoal;
$http.post('api/editGoal/' + this.goal.id, egoal)
A function in javascript is a block with its own scope. You need to use the vm concept. https://github.com/johnpapa/angular-styleguide/tree/master/a1#controlleras-with-vm
In the context of the changeGoal function, this.egoal is undefined.
Sending undefined as data to $http.post somehow serializes it to an empty array.
From the ngOptions docs:
When an item in the menu is selected, the array element or object property represented by the selected option will be bound to the model identified by the ngModel directive.
So, when you select one of the items from the dropdown, your ngModel egoal.period is not 1, or 2, or 3, or OT, it's {label: '1'}, {label: '2'}, etc. It's actually a pointer to the one of the items in your $scope.periods array.
Check out this plunker to get a better idea of what I mean:
http://embed.plnkr.co/9cJ2Hy/
Your PHP script is probably expecting a json object like this:
{
...
"period": '1',
...
}
But it's actually getting something more like this:
{
...
"period": "{\"label\": '1'}",
...
}
AngularJS uses JSON object by default in $http.post .
You can change the default setting by adding a correct Content-Type header to the config object:
headers : { 'Content-Type': 'application/x-www-form-urlencoded' }
UPDATE:
... by simply adding:
angular.module('myApp', [])
.config(function ($httpProvider) {
$httpProvider.defaults.headers.put['Content-Type'] = 'application/x-www-form-urlencoded';
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
})
Or another solution would be:
return $http({
method: 'POST',
url: "/yoururl/",
data:{
'param1': "Test",
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}}).then(function(result) {
console.log(result);
}, function(error) {
console.log(error);
});

UI-GRID display json data

At the moment I am retrieving data from the server.
[
{
id:1,
name:demo,
request: {
id: 1,
localCompany: {
id: 1
}
}
}]
[{ }, { }] so this is how my json object looks.
When I get call the $http service and put it in the gridOptions: {data: this.data}
I get this error in the console window: TypeError: newRawData.forEach is not a function.
data: ng.IPromise<any[]> = this.programService.getRequestsForProgram(this.model.id).then((data: any) => {
console.log(data);
return data;
});
gridOptions: {} = {
data: this.data ,
paginationPageSize: 5
//columnDefs: this.programCountryService.getHeaders()
};
This is the code I am using at the moment.
Any idea how I can get rid of this error? And is it possible that the grid only shows localCompany.Id and not the name:demo?
Try to put the data in $scope.data
Like $scope.data=getdata from server
and then
gridOptions: {} = {
data: $scope.data ,
paginationPageSize: 5
//columnDefs: this.programCountryService.getHeaders()
};
Put data into $scope and than to gridOptions.data = $scope.data.
If you want to show only data for localCompany.id you need to make definition for columnDefs for field request with custom template like:
'<div class="ui-grid-cell-contents">{{ COL_FIELD.id }}</div>'

How to push json data into array in angular js

How do i get data in $scope.moduleSelected into label in the treedata_avm array instead of the hardcoded values present in the array?
app.controller('treeController',['$http','$scope','dataService',function( $http,$scope,dataService){
$http.get('WS/tree').success(function(data,status){
$scope.modules=data;
$scope.moduleSelected = $scope.modules[0].MODULE_NAME;
$scope.moduleSelectedId = $scope.modules[0].ID;
$scope.moduleSelectedParentId = $scope.modules[0].PARENT_ID;
console.log($scope.modules);
console.log($scope.moduleSelected);
console.log($scope.moduleSelectedId);
console.log($scope.moduleSelectedParentId);
}).error(function(data){
$scope.modules=data || "Request failed";
console.log("Request failed "+ $scope.modules);
});
}]);
treedata_avm:
treedata_avm = [
{
label: 'Animal',
children: [
{
label: 'Dog',
}, {
label: 'Cat',
}, {
label: 'Hippopotamus',
}, {
label: 'Chicken',
children: ['White Leghorn', 'Rhode Island Red', 'Jersey Giant']
}
]
}]
You can listen to event 'onchange' on the field, that's bound to $scope.moduleSelected and change your json when input field is changed. But I can't see, why would you need something like this?
$http with its success promise resolve function returns data in the current format: response.data
Meaning in your case you should first set
$http.get('WS/tree').success(function(response){
$scope.modules = response.data;
$scope.treedata_avm = response.data
}).error(function (){...})
If you are going to use your treedata_avm on a view, then it should be on the $scope as in $scope.treedata_avm if not then just use it as a variable inside the controller
Also my advice would be to put all of this $http logic into a provider (factory, service, provider) and then invoke it from there.
The advice is to make controllers as thin as possible and put the logic inside the providers (factories, services, providers), thus making it reausable
Hope this helps.

Resources