I'm having an issue where I am trying to watch a certain element from my scope after the resolve is done. For some reason, it gets run when i run the second line from this snippet and I dont seem to be able to add this $watch during the "resolve".
I understand that promises are asynch, but how can I know when my resolve is done to then add the watch?
The variableToWatch can be changed either by code or in the UI (otherwise i would've just used ng-change="doWork()")
$scope.variableToWatch = $route.current.locals.data.initialValue;
$scope.listOfDependantData = $route.current.locals.data.items;
$scope.$watch('variableToWatch', function (newValue) {
myService.getNewDependantData(newValue).$promise.then(
function (items) {
$scope.listOfDependantData = items;
}
);
};
Update:
If you want to run your code only when it changes after the initial setting of value, you can use the second form of the watchFunc passed as the second argument to $scope.$watch:
$scope.$watch('variableToWatch', function (newValue, oldValue) {
if (typeof newValue !== 'undefined' && newValue !== oldValue) {
// Use the new value here ...
}
});
I don't fully follow the question, but I suspect that you want to watch the value $route.current.locals.data.initialValue instead of $scope.varibleToWatch?
In that case, you can use the alternate form of $scope.$watch with a function as the first argument:
$scope.$watch(function () { return $route.current.local.data.intialValue; }, function (newValue) {
// ...
};
Or, if you want to watch the variable on your $scope which is referenced to by the sting contained in $route.current.local.data.initialValue, then you can use this:
$scope.$watch(function () { return $scope[$route.current.local.data.intialValue]; }, function (newValue) {
// ...
};
Does this solve your problem?
Related
I've rendered a chart using highchart.js using solutions from a couple questions. I understand the basic use of directives. However, in the case of highchart.js, I don't quite understand this code here:
app.directive('highchart', function () {
var direc = {};
var link = function (scope, element, attributes) {
scope.$watch(function () {
return attributes.chart;
}, function () {
var charts = JSON.parse(attributes.chart);
$(element[0]).highcharts(charts);
})
}
direc.restrict = 'E';
direc.link = link;
direc.template = '<div></div>';
//the replace method replaces the content inside the element it is called
direc.replace = true;
direc.scope = {};
return direc;
})
The charts attribute will accept a JSON array of chart attributes.
Can someone explain what's happening inside the function? Thank you for reading.
The $watch is used to monitor the changes on a specific field. In the above case the attributes.chart is being watched for changes in the first argument in the $watch function and the second argument works with actually checking the modified data and performing manipulation on it.
You can also find further options that can be used by the $watch in the official angular docs: https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watch
$watch monitor the model chnanges, once the model chnages , updated values get from below code and as per requirement, required action can perform.
$scope.$watch('ng-model-name', function (newval, oldval) {
if (newval< 0) {
$('#modelCustomer').modal('show');
}
});
Simple task here, but not sure about the mistake.
My service:
app.factory('Progress', function () {
var data = {
progressPercentageLoaded: 0
};
return {
getProgress: function () {
return data.progressPercentageLoaded;
},
setProgress: function (progress) {
data.progressPercentageLoaded = progress;
}
};
});
I have one controller that is uploading a file, this one sets the progress value.
//in my controller
$scope.progressPercentageLoaded = {progress:0};
//a few lines down
function (evt) {
console.log(evt);
$scope.progressPercentageLoaded.progress = evt.loaded;
Progress.setProgress($scope.progressPercentageLoaded.progress);
My second controller should simply watch the service for changes and update the view, but it stays stuck at zero even though I confirm the upload is happening and that evt.loaded is changing.
$scope.progress = 0;
$scope.$watch(function () { return Progress.getProgress(); }, function (newValue, oldValue) {
if (newValue !== oldValue) {
$scope.progress = Math.min(100, parseInt(100 * newValue / $scope.size));
if($scope.progress == 100)
{
$scope.progressModalInstance.close();
window.location.reload();
}
}
});
That is, $scope.progress in second controller should update with the value of evt.loaded in the first controller, but it doesn't.
Thanks in advance for any guidance.
EDIT: I even added the third watch parameter as true but that didn't help either.
EDIT 2 : The code above actually works to the best of my knowledge, I believe something else was causing a problem as when I reverted the code to the above after editing it due to the answers, it suddenly worked like it should. Sorry about this.
using $rootScope.$broadcast will work better for this
app.factory('Progress', function ($rootScope) {
var data = {
progressPercentageLoaded: 0
};
return {
getProgress: function () {
$rootScope.$broadcast('Event');
return data.progressPercentageLoaded;
},
setProgress: function (progress) {
data.progressPercentageLoaded = progress;
}
};
});
In your second controller instead of using watch
something like
$rootScope.$on('Event', function(){
//your logic here
})
You are losing the reference because you are watching the Int value that you are updating every time, hence you are changing the reference. You have to watch the whole object progressPercentageLoaded.
You have to pass true as the last parameter of the $watch function so that the equality check is angular.equals. Otherwise, only reference equality is checked.
I'm not 100% sure, but Angular may not be aware of the file upload event. Try calling $apply:
$scope.$apply(function() {
Progress.setProgress($scope.progressPercentageLoaded.progress);
});
I tried to follow along with this example but my code never enters the callback with the newValue when the input changes for some reason. The only difference in my example and the example bin below is that I'm using a service to hold the value instead of a controller variable.
I've been trying to make it work but I can't wrap my head around it. What am I missing?
http://jsbin.com/yinadoce/1/edit?html,js,output
Note that I've excluded the input and the steps prior to the value being updated in the service as this works perfect. The issue is only that my watch doesn't understand when the value has changed in the service.
EDIT: Forgot to inject $scope in the controller when I pasted over the code, now it's complete.
Controller:
coForms.controller('CoFormsCtrl', ['$scope', 'coFormsInfo', function($scope, coFormsInfo) {
$scope.$watch(angular.bind(coFormsInfo.getInfo(), function() {
return coFormsInfo.getInfo();
}), function(newVal) {
console.log(newVal);
});
}]);
Service:
coForms.service('coFormsInfo', [function() {
var info = {
filteredList: []
}
this.setFilteredList = function(list) {
info.filteredList = list;
};
this.getInfo = function() {
return info;
};
}]);
The watcher is there to detect any changes in the variable you're watching. How can he watch something that is not... Strictly present like a return value?
I'm not sure about what I'm saying because I'm new to angular, but the logic seems false there. You need to watch something declared to detect some changes.
You should call your service to get your infos when you need them and watch for an info variable.
EDIT
My bad there is something like that but you should declare it in a function maybe like the example on the documentation
var food;
scope.foodCounter = 0;
expect(scope.foodCounter).toEqual(0);
scope.$watch(
// This function returns the value being watched. It is called for each turn of the $digest loop
function() { return food; },
// This is the change listener, called when the value returned from the above function changes
function(newValue, oldValue) {
if ( newValue !== oldValue ) {
// Only increment the counter if the value changed
scope.foodCounter = scope.foodCounter + 1;
}
}
);
Newbie quesiton, I read the document of rootscope.$watch. the syntax of $watchis
$watch(watchExpression, [listener], [objectEquality], [deregisterNotifier]);
But I see the examples use it like below.
var food;
scope.foodCounter = 0;
expect(scope.foodCounter).toEqual(0);
scope.$watch(
// This is the listener function
function() { return food; },
// This is the change handler
function(newValue, oldValue) {
if ( newValue !== oldValue ) {
// Only increment the counter if the value changed
scope.foodCounter = scope.foodCounter + 1;
}
}
);
What does it mean missing WatchExpression? thanks.
watchExpression can be both string or function - refer back to angularjs documentation as posted in the question. Given example as posted in the question will never trigger change handler because food is always undefined.
If you are using function as watchExpression, the function must return different value in order to trigger change handler. As documented in angularjs official document
Expression that is evaluated on each $digest cycle. A change in the
return value triggers a call to the listener.
Code Snippet
function Ctrl($scope) {
$scope.food = "Laksa";
$scope.foodCounter = 0;
$scope.$watch(
//this is watch expression using function
function (scope) {
return scope.food;
},
//this is listener - change handler
function (newValue, oldValue) {
console.log(newValue, oldValue);
if (newValue !== oldValue) {
// Only increment the counter if the value changed
$scope.foodCounter = $scope.foodCounter + 1;
}
});
}
example - http://jsfiddle.net/4atA2/2/
this listener function is equivalent to $scope.$watch('food',... because it don't have additional logic. You have flexibility to add additional logic checking to decide whether want to trigger change handler or not. For example, watch on two scope variable.
example - http://jsfiddle.net/5NLNa/5/
function (scope) {
if(scope.drink == "Milo") {
return scope.food;
}
},
Sometimes I end up $watching for a boolean expression to become true in controller (to do a redirect or some other magic that belongs to a controller).
(typescript)
$scope.$watch('aComplexBoolean && expressionWith && lotsAstuff', (newValue) => {
if (newValue) {
// do my stuff, e.g. redirect etc..
}
});
I was wondering, is there possibly a shorthand in AngularJS for this, I would really like to get rid of the extra clutter and just call for example $when('expr', () => { /* do stuff */ }) or something else equally nice and to the point.
No, there is no such shorthand, as shown by the $rootScope documentation. But you can create it yourself by modifying the $rootScope object:
var myApp = angular.module('MyApp', []);
myApp.run([
'$rootScope',
function ($rootScope)
{
$rootScope.$watchTrue = function (expression, callback)
{
// Here, `this` refers to the scope which called the function
return this.$watch(
expression,
function (newValue, oldValue)
{
if (newValue) {
callback(newValue, oldValue);
}
}
);
};
}
]);
No. But I prefer to use an early exit instead of wrapping in an if:
$scope.$watch('aComplexBoolean && expressionWith && lotsAstuff', (newValue) => {
if (!newValue) return;
// do my stuff, e.g. redirect etc..
});
It is also not uncommon to have multiple early exits and this pattern is much better than wrapping in an if.