ExtJS - Change field value without firing the "change" event - extjs

I'm writing a function in a ViewController which will reset all of the fields in a complex View. This view is using ExtJS 5 two-way data binding with a ViewModel. That's how I'm reseting the fields:
clearFields: function() {
var vm = this.getViewModel();
vm.set('name', '');
vm.set('address', '');
vm.set('port', '');
vm.set('active', false);
vm.set('dynamic', false);
vm.set('bandwidthOptimization', true);
vm.set('reverse', false);
vm.set('timeout', 60);
vm.set('camerasEnabled', 1);
vm.set('username', '');
vm.set('password', '');
vm.set('vendorGuid', '');
vm.set('modelGuid', '');
vm.set('subscriber', '');
vm.set('event', '');
vm.set('partition', '');
vm.set('instructions', '');
}
But each time I use the set method, it fires the change event of its field, which then is captured back by the controller and do other interactions with the page that are not wanted in this case. So I need to suppress this event from being triggered temporarily. How can I accomplish this?

If you were setting values on the fields directly (i.e. not via a viewmodel), perhaps you could use setRawValue. But if you need to keep doing it the way you quoted, then here is a solution:
In order to prevent a field from firing the change event, its private suspendCheckChange property needs to be greater than 0. Therefore you could implement a method to walk through your fields and increase the property before doing your reset, and then, once reset is done, get the property value back where it was. Example:
suspendChange: function(suspend) {
var fields = Ext.ComponentQuery.query('field', this.getView()),
i = 0;
for (; i < fields.length; i++) {
if (suspend) {
fields[i].suspendCheckChange++:
} else {
fields[i].suspendCheckChange--;
}
}
},
clearFields: function() {
this.suspendChange(true);
// do reset stuff
this.suspendChange(false);
}

Related

Toggling between $pristine and $dirty in AngularJS

I want to detect when a user has entered values into any form field by using the $dirty property and setting a flag accordingly. Not surprisingly, this works:
$scope.$watch('formDetails.$dirty', function() {
USR.userInputRecorded = true;
});
But I'd also like to detect when/if the user has emptied all fields and effectively restored the form to its original empty state. The snippet below does not work and I'm not sure why. Is there a way to watch for when the form changes back to "not dirty"?
$scope.$watch('formDetails.$pristine', function() {
USR.userInputRecorded = false;
});
Thanks.
Try this:
$scope.$watch('formDetails.$dirty', function(value) {
if (value === '') {
// field has been emptied;
your.form.$setPristine(true);
} else {
USR.userInputRecorded = true;
}
});

working on select but not on blur - EXTJS

I am newbie to ExtJS I have the following lines of code that is working fine on select event and now I am planning to add on blur event too.
autoResolve.on("select" || "blur", function (component, record, index) {
var fieldSet = utils.getComponentFromMngr(component.id.split("~")[0]);
if(autoResolveData.CURRSEL){ //Set previous selection property
var xmlElem = fieldSet.DomainXML.documentElement.childNodes[1];
xmlElem.setAttribute("PR_DOMAINTYPE",autoResolveData.FILL_SUBTYP);
xmlElem.setAttribute("PR_DOMAINID", record.get("ITEMID"));
xmlElem.setAttribute("PR_DOMAINVALUE", record.data.TITLE);
fieldSet.DomainObj.push({PRDomainType:autoResolveData.FILL_SUBTYP,PRDomainID:record.get("ITEMID"),PRDomainValue:record.data.TITLE});
}
it is still working fine on select event but not on blur event where am I going wrong please suggest
"select" || "blur" will return select, as you can find out if you type the following in browser console:
console.log("select" || "blur");
Furthermore, "blur" event does not have record as the second parameter. You would have to look how to get record and call the function with a valid record parameter.
What you want to achieve is roughly the following:
var myFunction = function (component, record, index) {
var fieldSet = utils.getComponentFromMngr(component.id.split("~")[0]);
if(autoResolveData.CURRSEL){ //Set previous selection property
var xmlElem = fieldSet.DomainXML.documentElement.childNodes[1];
xmlElem.setAttribute("PR_DOMAINTYPE",autoResolveData.FILL_SUBTYP);
xmlElem.setAttribute("PR_DOMAINID", record.get("ITEMID"));
xmlElem.setAttribute("PR_DOMAINVALUE", record.data.TITLE);
fieldSet.DomainObj.push({PRDomainType:autoResolveData.FILL_SUBTYP,PRDomainID:record.get("ITEMID"),PRDomainValue:record.data.TITLE});
}
};
autoResolve.on({
select:myFunction,
blur:function(component) {
var record = ... // your special magic here
return myFunction(component,record);
}
});

listening every time a model attribute sets

I have a backbone model like -
ModelA = Backbone.Model.extend({
this.set("prop1",true);
})
and View like -
ViewA = Backbone.View.extend({
initialize : function(){
this.listenTo(this.model,"change:prop1",this.changeProp1)l;
this.model.set("prop1",true);
},
changeProp1 : function(){
// callback doesn't call because I'm setting the same value
}
});
var model1 = new ModelA();
var view1 = new ViewA({model:model1});
Here the callback changeProp1 triggers whenever prop1 changes from true -> false -> true .
But I want to listen everytime whenever I'm setting the same value or different value.
I'd say it's best to leave the change event alone, and implement a new set event (or whatever you want to call it). After all, you want to be notified about things that aren't strictly 'changes'.
You could implement your own version of set() in your model which fires a custom 'set' event and then calls backbone's usual set method afterwards.
var MyModel = Backbone.Model.extend({
set: function(key, val, options) {
// Deal with single name/value or object being passed in
var changes;
if (typeof key === 'object') {
changes = key;
options = val;
} else {
(changes = {})[key] = val;
}
options || (options = {});
// Trigger 'set' event on each property passed in
for (var i = 0, l = changes.length; i < l; i++) {
this.trigger('set:' + changes[i], this, this.attributes[changes[i]], options);
}
// Call the usual backbone 'set' method
Backbone.Model.prototype.set.apply(this, arguments);
}
});
and then listen for your new event instead of (or as well as) 'change', where appropriate:
ViewA = Backbone.View.extend({
initialize : function(){
this.listenTo(this.model,"set:prop1",this.changeProp1)l;
this.model.set("prop1",true);
},
However, most of this code is just lifted from Backbone's default set method, and doesn't deal with some other issues such as some option flags and nested events. If you wanted to change the Backbone source itself, the line you want to look for is:
if (!_.isEqual(current[attr], val)) changes.push(attr);
(line 347 in version 1.0.0) and try removing that if clause.
(Code above isn't tested, sorry for any syntax errors)
For implementing above , you have to make changes in change function in backbone.js . Change checks whether the value of the property changed if yes than only it calls the binded function.

Force validation of entire form in AngularJS upon editing any portion of the form?

I have a form in which the validity depends upon the relationship between multiple textboxes. For example, if there are three textboxes, then the form is valid only if each textbox's integer value is greater than the previous textbox's integer value.
I'd like to set up this form so that if the user edits any of the textboxes, the entire form revalidates.
I've tried setting up ng-change=revalidate() on all the textboxes, with the following:
$scope.revalidate = function() {
var formData = $parse('signals');
var dataCopy = angular.copy(formData($scope));
formData.assign($scope, dataCopy);
};
I hoped that copying and reassigning the form's data would trigger revalidation, but it doesn't seem to work. How would I achieve this?
I solved this by creating a directive. In that directive, I set up a $watch on the concatenated values of all the textboxes. Then when that $watch sees a change in any of the textboxes, it revalidates the element. Since this directive is applied to all my textboxes, the entire form revalidates when any one of the textboxes is edited.
If someone has a more elegant solution than this, let me know.
link: function(scope, elm, attrs, ctrl) {
// when any of the intervals for this signal change, revalidate this interval
scope.$watch(
// loop through all the intervals for this signal, concatenate their values into one string
function() {
var intervals = [],
child = scope.$parent.$$childHead;
while (child !== null) {
console.log(child);
intervals.push(child.interval.end);
child = child.$$nextSibling;
}
return intervals.join();
},
function() {
validate(ctrl.$viewValue);
}
);
function validate(intervalDateTimeFromView) {
var valid = false;
// if this interval ends before or at the same time as the previous interval
if (scope.$$prevSibling && Number(intervalDateTimeFromView) <= Number(scope.$$prevSibling.interval.end))
{
ctrl.$setValidity('overlappingInterval', false);
return undefined;
} else {
ctrl.$setValidity('overlappingInterval', true);
return intervalDateTimeFromView;
}
}
ctrl.$parsers.unshift(validate);
ctrl.$formatters.unshift(validate);
}
It's not perfect, but it's what I'm working on at the moment:
$element.bind('blur', function() {
formCtrl[inputName].$dirty = true;
$scope.$emit('validate-refresh');
});
$scope.$on('validate-refresh', function() {
var control = formCtrl[inputName];
if (control.$dirty) {
control.$setViewValue(control.$viewValue);
}
}

Truly change a model attribute silently in Backbone.js?

Is there a way I can change attributes on a model without ever firing a change event? If you pass {"silent":true} right now, the next time an attribute is changed, the silent change event will be triggered. Can I change an attribute safely without the change event ever being triggered?
from change, Backbone 0.9.2:
// Silent changes become pending changes.
for (var attr in this._silent) this._pending[attr] = true;
// Silent changes are triggered.
var changes = _.extend({}, options.changes, this._silent);
this._silent = {};
for (var attr in changes) {
this.trigger('change:' + attr, this, this.get(attr), options);
You can change model attributes directly using model.attributes['xyz'] = 123.
I think the cleanest way if you really want to default to silent (but still be able to do silent:false) sets would be to override set. This should do it:
var SilentModel = Backbone.Model.extend({
set: function(attrs, options) {
options = options || {};
if (!('silent' in options)) {
options.silent = true;
}
return Backbone.Model.prototype.set.call(this, attrs, options);
}
});
item.set(
{
sum: sum
,income: income
},
{silent: true}
);
since backbone 0.9.10

Resources