I am working in a project and I am having some problems to work with some variables in the controller. This is the controller's code
angular.module('wc-general-informe-notas')
.controller('AnalisisEvaluacionController', ['$scope','$state','urlBasePartials', 'idColegio', 'anio', 'EvaluacionFactory',
function ($scope, $state, urlBasePartials, idColegio, anio, EvaluacionFactory) {
//Default ranges that clasifies
$scope.scoreRange = [
{level: "Very low", from: 1, to: 3.9},
{level: "Low", from: 4, to: 4.9},
{level: "High", from: 5, to: 5.9},
{level: "Excellent", from: 6, to: 7},
];
$scope.setRange = function () {
$scope.ranges = $scope.scoreRange;
}
$scope.informe =13;
$scope.levels = [];
$scope.idColegio = idColegio;
$scope.anio = anio;
$scope.nombreCurso = $('#curso option:selected').text();
$scope.casillero = $('#casillero option:selected').text();
$scope.evaluation = null;
$scope.setRange();
$scope.generateReport = function () {
EvaluacionFactory.patch({
idEvaluacion: $scope.filtroCasillero,
idSector: $scope.filtroAsignatura,
idCurso: $scope.filtroCurso,
idEvaluacionCursoSector: $scope.evaluacionCs[$scope.filtroPeriodo],
'expand[]': ['r_evaluacion_nota','nota_detalle','r_nota_alumno','alumno_detalle']
}, function (evaluation) {
$scope.evaluation = evaluation;
$scope.adjustLevels();
})
}
$scope.getRange = function (value) {
for (var i in $scope.ranges)
{
var range = $scope.ranges[i];
if (value == range.from || value == range.to || (value > range.from && value < range.to))
return range.level;
}
}
function init() {
$scope.profesor = null;
$scope.$parent.cursos_lista.forEach(function (curso) {
if(curso.id == $scope.filtroCurso)
{
if(curso.profesor != undefined)
{
var profesor = curso.profesor.usuario_detalle[0];
$scope.profesor = profesor.nombres + " " + profesor.apellido_paterno + " " + profesor.apellido_materno;
$scope.profesor = $scope.profesor.toString().toLowerCase();
}
}
})
if ($scope.ranges == undefined)
$scope.setRange();
if ($scope.filtroCasillero != null)
$scope.generateReport();
}
init();
$scope.adjustLevels = function () {
for(var i in $scope.evaluation.scores)
$scope.levels[$scope.evaluation.scores[i].id] = $scope.getRange($scope.evaluation.scores[i].valor);
}
}]);
What this controller does is get data from a factory which brings all the scores that an evaluation has. I render all the data correctly in the view, the problem is that in the view the user can modify $scope.ranges and then click a button (ng-click) that calls $scope.adjustLevels which should show the new level according to the new $scope.ranges' values.
Every time $scope.adjustLevels is called throws an error which said that
$scope.evaluation is null, even though there is no problem when is called after receiving the data from the factory.
It seems that I can't access all those variables I have set previously.
What can be happening? I hadn't had this sort of problems before.
I have tried adding console.log($scope.levels) and console.log($scope.evaluation) and it shows their content only when the method init() is called but not when I called it from the button I have in the view. When I do that is shows an empty array and null which are the values defined by default at the beginning
You expect that the $scope.generateReport() will set the $scope.evaluation but then you have this condition
if ($scope.filtroCasillero != null)
$scope.generateReport();
The $scope.filtroCasillero is not declared which makes the $scope.generateReport() never to be run and thats why the $scope.evaluation is null
Related
I am new for AngularJS and I am trying to access function parameter value inside nested angular for each loop , but that variable gets undefined error. here is my code .
var pieChart = function (_data, _fieldName) {
var data = _data;
var cost_max = 0;
var cost_min = 99999;
angular.forEach(groupBy($scope.api_data, _fieldName), function (obj, index) {
var total = 0;
var name = '';
angular.forEach(obj, function (row, i) {
name = row._fieldName;
total += 1;
})
data.push([name, total]);
if (cost_max < obj.cost) cost_max = obj.cost;
if (cost_min > obj.cost) cost_min = obj.cost;
})
$scope.chart.data = data;
$scope.loaded = 1;
}
row._fieldName is undefined here , what was the issue ? kindly help me.
var groupBy = function (xs, key) {
return xs.reduce(function (rv, x) {
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
};
In your second angular.forEach loop, you have to replace row._fieldName with row[_fieldName].
angular.forEach(obj, function (row, i) {
name = row[_fieldName];
total += 1;
})
By writing row._fieldName, you try to get the key named _fieldName from object row instead of the real field.
Little JSFiddle
My code has been working well until I introduced local storage. What I do is: when device is ready check if the values exist, if so get them. In the body of a function I assign a value to that variable scope and that's where I get this error.
$ionicPlatform.ready(function() {
if (localStorageService.get("modelTrue") == null) {
$scope.userModal.show();
localStorageService.set("modelTrue", "true")
}
else {
//Parameter to restore:
if(localStorageService.get("first") != null){
$scope.data.firstDisplay = JSON.parse(localStorageService.get("first"));
}
};
$scope.scanBarcode = function() {
$scope.data.firstDisplay = {'src' : 'img/1.png'}; //this is where I get the error
localStorageService.set("first", JSON.stringify($scope.data.firstDisplay));
}
When I call the last function I get the error: "TypeError: Cannot set property 'firstDisplay' of null".
I don't understand this behaviour. I am simply setting a variable to a value.
What might this mean?
The null comes from console.log($scope.data);
You need to declare $scope.data ={}; otherwise it is always null,
$ionicPlatform.ready(function() {
$scope.data ={};
if (localStorageService.get("modelTrue") == null) {
$scope.userModal.show();
localStorageService.set("modelTrue", "true")
} else {
//Parameter to restore:
if (localStorageService.get("first") != null) {
$scope.data.firstDisplay = JSON.parse(localStorageService.get("first"));
}
};
$scope.scanBarcode = function() {
$scope.data.firstDisplay = {
'src': 'img/1.png'
}; //this is where I get the error
localStorageService.set("first", JSON.stringify($scope.data.firstDisplay));
}
I have a service:
storeApp.service('currentCustomer',function($http) {
this.customerID = 0;
this.customerInfo = {}
this.customerAttributes = {}
this.getCustomerInfo = function () {
if (this.customerID != 0) {
$http.get('/customers/' + this.customerID).
then(function (result) {
this.customerInfo = result.data[0]
})
}
}
and a controller:
storeApp.controller('storeList',function($scope,$http,currentCustomer) {
$scope.changeCust = function changeCust(id) {
currentCustomer.customerID = id;
currentCustomer.getCustomerInfo()
console.log("After Change customer:")
console.log(currentCustomer)
}
$scope.selectedStore = currentCustomer
});
If I try to access selectedStore.customerID, I get values.
If I try to access selectedStore.customerInfo, I get an empty array, even though when i put console logging in to check the values, it says they are assigned.
Any ideas what I'm doing wrong? Thanks everyone.
You are manually assigning a value to CustomerId, and your service method is assigning a value to customerInfo. Except this in the service method, is not the same as this in the service. You should instantiate a var self = this; reference inside the service and use this value in all your object manipulation. eg: self.customerInfo = ....
Your reference for this has been changed inside function. first store this reference in some variable and then assign properties, some prefer to use the word self but I prefer service
storeApp.service('currentCustomer',function($http) {
var service = this;
service.customerID = 0;
service.customerInfo = {}
service.customerAttributes = {}
service.getCustomerInfo = function () {
if (service.customerID != 0) {
$http.get('/customers/' + this.customerID).
then(function (result) {
service.customerInfo = result.data[0]
});
}
}
In my Service i have the vars i want to display and the getters for it:
var docsLoaded = 0;
var docsToLoad = null;
pouchService.getDocsLoaded = function () {
return docsLoaded;
};
pouchService.getDocsToLoad = function () {
return docsToLoad;
};
While the service is syncing, i want to count the synced docs
pouchService.syncNow = function () {
var foundLastSeq = false;
docsLoaded = 0;
docsToLoad = null;
remoteDB.info().then(function (remoteInfo) {
function findOutDiff(localPosition) {
docsToLoad = (remoteInfo.update_seq - localPosition) + 1;
console.log("docs to load: " + docsToLoad);
}
// start Sync progress
sync = localDB.sync(remoteDB, {live: false})
.on('change', function (info) {
console.log('AI change: ');
console.log(info);
if (info.direction === 'pull') {
if (foundLastSeq === false) {
foundLastSeq = true;
findOutDiff(info.change.last_seq);
}
}
console.log(docsLoaded + " from " + docsToLoad);
docsLoaded++;
})
In my HTML i want to display the progress like this:
{{pouchService.getDocsLoaded()}} from {{pouchService.getDocsToLoad()}}
Now i get sometimes a value from getDocsLoaded, but mostly its zero. When I cancel the Syncprogress i get the value where it's stopped.
So i get the value before it really starts and when it's over, but i want it during the sync progress. (on the console my my progressinfos are working as expected)
Any ideas?
The problem is in applying scope. Jim wrote a nice article about this problem:
jimhoskins.com/2012/12/17/angularjs-and-apply.html
Solved it:
$rootScope.$apply(function () {
docsLoaded++;
});
I'm having trouble decorate the objects in my list returned by $asArray in angularfire with a new method (not decorating the array itself).
The angularfire documentation seems to suggest that the right way to do this is to override the $$added method in the factory for $FirebaseArray, returning a new object that either encapsulates or extends the snapshot that gets passed in to that method. From the documentation:
// an object to return in our JokeFactory
app.factory("Joke", function($firebaseUtils) {
function Joke(snapshot) {
this.$id = snapshot.name();
this.update(snapshot);
}
Joke.prototype = {
update: function(snapshot) {
// apply changes to this.data instead of directly on `this`
this.data = snapshot.val();
},
makeJoke: function() {
alert("Why did the " + this.animal + " cross the " + this.obstacle + "?");
},
toJSON: function() {
// since we didn't store our data directly on `this`, we need to return
// it in parsed format. We can use the util function to remove $ variables
// and get it ready to ship
return $firebaseUtils.toJSON(this.data);
}
};
return Joke;
});
app.factory("JokeFactory", function($FirebaseArray, Joke) {
return $FirebaseArray.$extendFactory({
// change the added behavior to return Joke objects
$$added: function(snap) {
return new Joke(snap);
},
// override the update behavior to call Joke.update()
$$updated: function(snap) {
this.$getRecord(snap.name()).update(snap);
}
});
});
However, when I do this in my code, nothing ever gets added to the array, although I can see from outputting to the console that it is getting called.
var printMessageObjConstructor = function(snap) {
this.$id = snap.name();
this.snapshot = snap;
this.$update = function(snap) {
this.snapshot = snap;
};
this.printMessage = function() {
return this.author + "'s question is: " + this.body;
};
};
var ref = new Firebase("https://danculley-test.firebaseio.com/questions");
//What Am I Doing Wrong Here?
var arrayFactory = $FirebaseArray.$extendFactory({
$$added: function(snap, prevChild) {
var x = new printMessageObjConstructor(snap);
console.log("I am being called from FirebaseDecoratedCtlOverloadAddedinNewObj.");
return x;
},
$createObject: function(snap) {
return new printMessageObjConstructor(snap);
},
$$updated: function(snap) {
var i = this.$indexFor(snap.name());
var q = this.$list[i];
q.$update(snap);
}
});
var sync = $firebase(ref, {arrayFactory:arrayFactory});
var list = sync.$asArray();
list.$loaded(function(list) {
$scope.questions = list;
});
I've set up a new plunk stripped down to show the issue with a couple other use cases that I've tried. (The actual method I'm adding is more complex and isn't related to the view, but I wanted to do something simple to reproduce the issue.)
I think the issue is that I don't quite understand what exactly $$added is supposed to return, or what additional behavior beside returning the value to be stored $$added is supposed to have. There also doesn't really seem to be an $$added on the prototype or on $FirebaseArray to call as a super to get the default behavior. Can someone point me in the right direction?
UPDATE
For the benefit of others, after reviewing the like that Kato posted, I was able to solve the issue by adding the following, almost all copied directly from the source except for the commented line below.
$$added: function(snap, prevChild) {
var i = this.$indexFor(snap.name());
if( i === -1 ) {
var rec = snap.val();
if( !angular.isObject(rec) ) {
rec = { $value: rec };
}
rec.$id = snap.name();
rec.$priority = snap.getPriority();
$firebaseUtils.applyDefaults(rec, this.$$defaults);
//This is the line that I added to what I copied from the source
angular.extend(rec, printMessageObj);
this._process('child_added', rec, prevChild);
}
}
For the benefit of others, after reviewing the link that Kato posted, I was able to solve the issue by adding the following, almost all copied directly from the source except for the commented line below.
$$added: function(snap, prevChild) {
var i = this.$indexFor(snap.name());
if( i === -1 ) {
var rec = snap.val();
if( !angular.isObject(rec) ) {
rec = { $value: rec };
}
rec.$id = snap.name();
rec.$priority = snap.getPriority();
$firebaseUtils.applyDefaults(rec, this.$$defaults);
//This is the line that I added to what I copied from the source
angular.extend(rec, printMessageObj);
this._process('child_added', rec, prevChild);
}
}