my html code is :
<select ng-model='refresh_rate' ng-change="onRefreshRateChange()">
<option value='10000'>10</option>
<option value='30000' selected>30</option>
<option value='60000'>60</option>
<option value='180000'>180</option>
<option value='300000'>300</option>
</select>
and in my angular controller is :
var intervaL = $interval(function(){
//[here]
//after run every times i want update delay to $scope.refresh_rate
}, $scope.refresh_rate);
see this line in top code :
//here i want update delay time to $scope.refresh_rate
now i want a code that put it Instead of this line
To change the $interval rate you need to stop one $interval and start another.
Without going into particulars of whether the last $interval call should fire or cancel immediately - I'll let you handle that on your own - you can do the following:
var p = $interval(doSomething, $scope.refresh_rate);
$scope.$watch("refresh", function(){
$interval.cancel(p);
p = $interval(doSomething, $scope.refresh_rate);
});
function doSomething(){
//...
}
plunker
EDIT:
You can also certainly do this in onRefreshRateChange instead of $scope.$watch. The difference is whether you care to change $scope.refresh_rate outside of your <select> - this is where you would use $watch vs. only in response to a change in <select>
Use a $timeout loop.
function loop(fn) {
$timeout(function() {
if (!$scope.stopBefore) {
fn();
$scope.stopAfter || loop(fn);
}
, $scope.refresh);
}
loop(doSomething);
Related
I am working on an ASP.Net MVC page that uses a dropdown which currently uses the ng-repeat tag. I'm working to solve the problem where the dropdown does not correctly select the current model value when the page loads so I switched the dropdown to use ng-options.
My new dropdown looks like this:
<select id="one" ng-model="data.CommandProvider"
ng-options="item.ident as item.ProviderName for item in providers">
</select>
When the page loads my new select displays as a large empty rectangle. It's approximately the width and height to match the three items it should contain but it's not a dropdown. No options and no dropdown button.
However, when I follow the new dropdown with the old dropdown like so:
<select id="one" ng-model="data.CommandProvider"
ng-options="item.ident as item.ProviderName for item in providers">
</select>
<select id="two" ng-model="data.CommandProvider">
<option ng-repeat="opt in providers track by opt.ident"
value="{{opt.ident}}">
{{opt.ProviderName}}
</option>
</select>
BOTH dropdowns load their options correctly but NEITHER dropdown correctly displays the current value of the model.
If the page only contains the old dropdown based on ng-repeat that dropdown displays correctly.
I don't understand what could cause such behavior in ng-options and what would cause the dropdowns to never correctly represent the model on page load?
ADDED: So the previous author had mismatched HTML tags and that was causing the error with the new dropdown - why it didn't break the original I don't know. That being said the new dropdown STILL does not display the value of the model when the page is loaded.
So after working this problem for too long this is the solution that worked for me:
There are three http requests in play: one for each select input and one for the model data and whenever the model data returned before the select data one or both of the select would be out of sync with the model. My solution was to synchronize the data requests.
The select inputs:
<select ng-model="data.Connection">
<option ng-repeat="opt in connections track by opt.ident" value="{{opt.ident}}">{{opt.ConnectionName}}</option>
</select>
<select id="two" ng-model="data.CommandProvider">
<option ng-repeat="opt in providers track by opt.ident" value="{{opt.ident}}">{{opt.ProviderName}}</option>
</select>
The javascript:
// connection and provider data variables
$scope.providers;
$scope.connections;
// function to retrieve connection dropdown data
$scope.getConnections = function () {
$scope.getApiData('GetConnections',
{}, function (data) {
$scope.connections = data;
});
}
// function to retrieve the provider dropdown data
$scope.getProviders = function () {
$scope.getApiData('GetProviders',
{}, function (data) {
$scope.providers = data;
});
}
// retrieve the primary page data
$scope.getCommandData = function () {
$scope.getApiCommandDataV1('GetCommandById',
{Id: #ViewBag.ID},
function (data) {
$scope.data = data;
});
}
// retrieves data from the core api
$scope.getApiData = function (alias, params, successFn, errorFn = null) {
var qdata = { SqlAlias: alias, SqlParameters: params };
if (errorFn == null) {
$http.post('/api/request', qdata).success(successFn);
} else {
$http.post('/api/request', qdata).success(successFn).error(errorFn);
}
}
// function to request the data for the page
$scope.init = function () {
$scope.getConnections();
}
// set a watch on the connections variable to fire when the data
// returns from the server - this requests the Providers information.
$scope.$watch('connections', function (newValue, oldValue, scope) {
if (newValue == undefined || newValue == null)
return;
$scope.getProviders();
}, true);
// set a watch function on the providers variable to fire when the data
// returns from the server - this requests the primary data for the Command.
$scope.$watch('providers', function (newValue, oldValue, scope) {
if (newValue == undefined || newValue == null)
return;
$scope.getCommandData();
}, true);
// initialize the page logic and data
$scope.init();
As you can see my use of $scope.$watch forces the data requests to be synchronous rather than asynchronous and using this method insures the two select inputs are correct every time the web page loads.
Feel free to comment on my coding here as there may be better ways to address this problem - just keep in mind that I have only been working with JavaScript and Angular for about a month.
I followed a description from another answer in order to cancel ng-change on a select dropdown. The code should stop changing year if the user has filled out some numbers in week 53, if the year he switches to does not contain a week 53. This code works, but only the first time. Can anyone explain why? My guess is that it has something to do with changing the wrong scope, but since I cannot pass the scope as a parameter to ng-change I'm really not sure...
This is HTML:
<select data-ng-change="updateYear('{{Year}}');" data-ng-model="Year">
<option value="2012">2012</option>
<option value="2013">2013</option>
...
</select>
This is the controller:
$scope.updateYear = function (oldYear) {
hasValuesInW53($scope.selectedProgram.Uid, function (hasW53Values) {
var has54weeks = ['2015', '2020', '2026', '2032', '2037'];
if ($.inArray(oldYear, has54weeks) > -1 && //old year has 53 weeks
$.inArray($scope.Year, has54weeks) == -1 && //new year does not have 53 weeks
hasW53Values //has values in W53
) {
$scope.Year = oldYear;
}
else {
$scope.updateProgram();
}
});
This is what I do:
Switch 2020 to 2019 -> Works ok, the cancel code is triggered and GUI
is changed back. Swotch 2020 to 2019 again -> Does not work. Cancel
code is still triggered, but it's not reflected in GUI).
I found a dirty workaround in order to solve the problem. As suspected, in the original solution, the wrong scope is referenced, and I could not get the correct one since ng-change does not support passing $event where I can reference the correct scope.
My workaround is adding ng-focus, storing the event, and use this to access the correct scope. Dirty, but works.
HTML:
<select data-ng-model="Year" data-ng-focus="yearFocusCallback($event)" data-ng-change="updateYear('{{Year}}');">
<option value="2012">2012</option>
<option value="2013">2013</option>
...
</select>
CONTROLLER:
$scope.yearChangeEvent = null;
$scope.yearFocusCallback = function ($event) {
$scope.yearChangeEvent = $event;
};
$scope.updateYear = function (oldYear) {
hasValuesInW53($scope.selectedProgram.Uid, function (hasW53Values) {
var has54weeks = ['2015', '2020', '2026', '2032', '2037'];
if ($.inArray(oldYear, has54weeks) > -1 && //old year has 53 weeks
$.inArray($scope.Year, has54weeks) == -1 && //new year does not have 53 weeks
hasW53Values //has values in W53
) {
angular.element($scope.yearChangeEvent.target).scope().Year = oldYear;
}
else {
$scope.updateProgram();
}
});
}
My guess is, its because you are mixing angular and jquery and be ready to get unexpected results whenever you are doing that because angular is data driven and jquery is deals with the DOM elements directly. Try using angular.forEach or array.indexOf instead of $.inArray
I have an ng-repeat that creates several widgets, each with it's own select dropdown.
<div ng-repeat="item in widget.items" class="col-md-6">
<select ng-model="item.chosenTag"
ng-change="widget.updateTag(item)"
ng-class="widget.getButtonClass(item.tag, item.id)">
<option value="companies"
ng-selected="{{item.tag == 'companies'}}"
changed="companies">companies</option>
<option value="news"
ng-selected="{{item.tag == 'news'}}"
changed="news">news</option>
<option value="people"
ng-selected="{{item.tag == 'people'}}"
changed="people">people</option>
</select>
</div>
As the view is loaded, the ng-class="widget.getButtonClass(item.tag, item.id)" calls a function to check if 2 values are met, then sets ng-class to either btn-success or btn-default.
// This checks the view after load to change the class on each widget select
var vm = this;
vm.getButtonClass = function(tag, id) {
console.log('in getButtonClass');
if (tag && id) {
return 'btn-success';
} else {
return 'btn-default';
}
};
Next if the user now updates a select within any widget, ng-change will update to the correct value.
However I need to somehow re-run the ng-class check or rather just go ahead and add btn-success to the select without having to refresh the page.
How would you go about accomplishing this?
Is there a way to do something like this?
ng-class="{ functionToUpdateAll | boolean based on ng-change }"
Is there any specific reason that you need to call the function? Why dont you bind directly to those variables?
ng-class="'btn-success':item.tag && item.id, 'btn-default': !(item.tag && item.id)"
In that way you take advantage of mutual binding i.e. whenever the item.tag or item.id are changed, the class will be evaluated accordingly.
I suggest that instead of calling the function in ng-class, just assign it to a variable:
<select ng-model="item.chosenTag"
ng-change="widget.updateTag(item)"
ng-class="mySelectClass">
And in your updateTag function in the controller update that variable:
vm.updateTag = function(item) {
if (item.tag && item.id) {
vm.mySelectClass = 'btn-success';
} else {
vm.mySelectClass = 'btn-default';
}
};
I have my select like so
<select ng-model="id_select" ng-options="fide.id as fide.name for fide in fides" ng-change="loadInfo()">
<option value="" selected disabled>Seleccionar</option>
</select>
And in my controller I have this
RestService.getFides().then(function(fides){
$scope.id_select = fides;
if(typeof $rootScope.selected_id !== 'undefined')
{
$scope.id_select = $rootScope.selected_id
}
});
$scope.loadInfo = function() {
alert("triggered!!");
}
My select is loading as expected with fides but when I try to set my select value with $rootScope's value ng-change function loadInfo() is not triggered but when I select in my view it works fine.
Any ideas of what am I doing wrong?
Thank you all in advance for your help :)
From the documentation for ngChange:
Evaluate the given expression when the user changes the input. The expression is evaluated immediately, unlike the JavaScript onchange event which only triggers at the end of a change (usually, when the user leaves the form element or presses the return key). The expression is not evaluated when the value change is coming from the model.
You need to call your event handler manually if you are changing the model programatically:
if (typeof $rootScope.selected_id !== 'undefined') {
$scope.id_select = $rootScope.selected_id;
$scope.loadInfo();
}
I have an input field, where I want to apply the variant of ngChange.
The input field is sort of binding with an ajax call, when user changes the input, the server side will process the data, however, I don't wanna make the call too often.
Say the user wanna input a really string, I want the call be made only after user finishes the word he is about to type.
Nevertheless, I don't wanna use event such as blur. What would be a better way to implement this, rather than setTimeout?
Use ng-model-options in Angular > 1.3
<input type="text"
ng-model="vm.searchTerm"
ng-change="vm.search(vm.searchTerm)"
ng-model-options="{debounce: 750}" />
Without ng-model-options -- In markup:
<input ng-change="inputChanged()">
In your backing controller/scope
var inputChangedPromise;
$scope.inputChanged = function(){
if(inputChangedPromise){
$timeout.cancel(inputChangedPromise);
}
inputChangedPromise = $timeout(taskToDo,1000);
}
Then your taskToDo will only run after 1000ms of no changes.
As of Angular 1.3, you could use Angular ng-model-options directive
<input ng-change="inputChanged()" ng-model-options="{debounce:1000}">
Source: https://stackoverflow.com/a/26356084/1397994
Write your own directive- this will only run the commands on myText based on the conditions you set
<input my-change-directive type="text ng-model="myText" />
.directive('myChangeDirective',function() {
return {
require : 'ngModel',
link : function($scope,$element,$attrs) {
var stringTest = function(_string) {
//test string here, return true
//if you want to process it
}
$element.bind('change',function(e) {
if(stringTest($attrs.ngModel) === true) {
//make ajax call here
//run $scope.$apply() in ajax callback if scope is changed
}
});
}
}
})