/** * This class is created to manage a direct bind. `Ext.app.ViewModel` returns this from * its {@link Ext.app.ViewModel#method-bind bind} method. */Ext.define('Ext.app.bind.Binding', { extend: 'Ext.app.bind.BaseBinding', /** * @cfg {Boolean} [deep=false] * Normally a binding is only notified of changes to its bound property, but if that * property is an object it is sometimes helpful to be notified of changes to its * properties. To receive notifications of changes to all properties of a bound object, * set this to `true`. * @since 5.0.0 */ constructor: function(stub, callback, scope, options) { var me = this; me.callParent([ stub.owner, callback, scope, options ]); me.stub = stub; me.depth = stub.depth; // We need to announce the current value, so if the stub is available // will generate its own announcement to all bindings) then we need to schedule if (stub.isAvailable() && !stub.scheduled) { me.schedule(); } }, /** * Destroys this binding. No further calls will be made to the callback method. No * methods should be called on this binding after calling this method. * @param {Boolean} [fromParent] (private) * @since 5.0.0 */ destroy: function(fromParent) { var me = this, stub = me.stub; if (stub && !fromParent) { stub.unbind(me); me.stub = null; } me.callParent(); }, /** * Binds to the `validation` association for the bound property. For example, when a * binding is bound to something like this: * * var binding = viewModel.bind('{theUser.name}', ...); * * The validation status for the "name" property can be requested like so: * * var validationBinding = binding.bindValidation(fn, scope); * * Calling this method in the above example would be equivalent to the following bind: * * var validationBinding = viewModel.bind('{theUser.validation.name}', fn, scope); * * The primary reason to use this method is in cases where the original bind expression * is not known. * * For example, this method is used by `Ext.form.field.Base` when given the * `{@link Ext.Component#modelValidation modelValidation}` config is set. As such it * not common for users to need to call this method. * * @param {Function} callback The function to call when the validation changes. * @param {Object} [scope] The scope on which to call the `callback`. * @return {Ext.app.bind.Binding} A binding to the validation of the bound property. * @since 5.0.0 */ bindValidation: function(callback, scope) { var stub = this.stub; return stub && stub.bindValidation(callback, scope); }, /** * Bind to a model field for validation * @param {Function/String} callback The function to call or the name of the function on the * scope * @param {Object} scope The scope for the callback * @return {Ext.app.bind.Binding} The binding, if available * * @private */ bindValidationField: function(callback, scope) { var stub = this.stub; return stub && stub.bindValidationField(callback, scope); }, /** * Returns the diagnostic name for this binding. * @return {String} * @since 5.0.0 */ getFullName: function() { return this.fullName || (this.fullName = '@(' + this.stub.getFullName() + ')'); }, /** * Returns the current value of the bound property. If this binding is not * {@link #isAvailable available} the value will be `undefined`. * @return {Mixed} The value of the bound property. * @since 5.0.0 */ getValue: function() { var me = this, stub = me.stub; return stub && stub.getValue(); }, /** * Returns `true` if the bound property is available. If this returns `false`, * it generally means the value is not reachable because the a parent value is * not present. * @return {Boolean} * @since 5.1.2 */ isAvailable: function() { var stub = this.stub; return stub && stub.isAvailable(); }, /** * Returns `true` if the bound property is loading. In the general case this means * that the value is just not available yet. In specific cases, when the bound property * is an `Ext.data.Model` it means that a request to the server is in progress to get * the record. For an `Ext.data.Store` it means that * `{@link Ext.data.Store#method-load load}` has been called on the store but it is * still in progress. * @return {Boolean} * @since 5.0.0 */ isLoading: function() { var stub = this.stub; return stub && stub.isLoading(); }, /** * This method returns `true` if this binding can only be read. If this method returns * `false` then the binding can be set using `setValue` (meaning this binding can be * a two-way binding). * @return {Boolean} * @since 5.0.0 */ isReadOnly: function() { var stub = this.stub, options = this.options, ret = true; if (!(options && options.twoWay === false)) { if (stub) { ret = stub.isReadOnly(); } } return ret; }, /** * Tells the bound property to refresh itself. This has meaning when the bound property * is something like an `Ext.data.Model` and an `Ext.data.Store` but does nothing in * most cases. * @since 5.0.0 */ refresh: function() { // TODO - maybe nothing to do here but entities/stores would have work to do }, /** * Sets the value of the bound property. This will throw an error in debug mode if * this binding `isReadOnly`. This method will climb to set data on * a parent view model of this binding if appropriate. See "Inheriting Data" in the * {@link Ext.app.ViewModel} class introduction for more information. * @param {Mixed} value The new value. * @since 5.0.0 */ setValue: function(value) { //<debug> if (this.isReadOnly()) { Ext.raise('Cannot setValue on a readonly binding'); } //</debug> this.stub.set(value); }, privates: { getDataObject: function() { var stub = this.stub; return stub && stub.getDataObject(); }, getRawValue: function() { var me = this, stub = me.stub; return stub && stub.getRawValue(); }, isDescendantOf: function(item) { var stub = this.stub; return stub ? (item === stub) || stub.isDescendantOf(item) : false; }, react: function() { this.notify(this.getValue()); }, schedule: function() { // If the parent stub is already scheduled, then we will be // called when the stub hits the next tick. if (!this.stub.scheduled) { this.callParent(); } }, sort: function() { var stub = this.stub; stub.scheduler.sortItem(stub); // Schedulable#sort === emptyFn // me.callParent(); } }});