Last active
March 23, 2016 05:26
-
-
Save koemeet/d848368a8cc5db072174 to your computer and use it in GitHub Desktop.
Bug observer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Ember from 'ember'; | |
export default Ember.Controller.extend({ | |
appName: 'Ember Twiddle', | |
// using ember data records | |
channels: function() { | |
return [ | |
this.get('store').createRecord('channel', { name: 'First channel' }), | |
this.get('store').createRecord('channel', { name: 'Second channel' }) | |
]; | |
}.property(), | |
// holds simple ember objects to showcase a working example | |
workingOwner: Ember.Object.create({ | |
objects: [] | |
}), | |
// using simple ember objects | |
working: [ | |
Ember.Object.create({ name: 'Object 1 ' }), | |
Ember.Object.create({ name: 'Object 2' }) | |
], | |
// this one is called multiple times, while the property it | |
// is observing is set only once. | |
valueDidChange: function() { | |
console.log('value did change'); | |
}.observes('model.channels.[]'), | |
// the same setup as the one above, but this one is called only once, as you would expect. | |
workingDidChange: function() { | |
console.log('working did change'); | |
}.observes('workingOwner.objects.[]') | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Ember from 'ember'; | |
export default Ember.Route.extend({ | |
model() { | |
return this.get('store').createRecord('product', { | |
id: 1, | |
name: 'A product' | |
}); | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import DS from 'ember-data'; | |
export default DS.Model.extend({ | |
name: DS.attr('string'), | |
product: DS.belongsTo('channel') | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import DS from 'ember-data'; | |
export default DS.Model.extend({ | |
name: DS.attr('string'), | |
channels: DS.hasMany('channel') | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"version": "0.6.4", | |
"EmberENV": { | |
"FEATURES": {} | |
}, | |
"options": { | |
"enable-testing": false | |
}, | |
"dependencies": { | |
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js", | |
"ember": "2.4.1", | |
"ember-data": "beta", | |
"ember-template-compiler": "2.4.1" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Ember from 'ember'; | |
import XSelectComponent from '../x-select/component'; | |
var isArray = Ember.isArray; | |
/** | |
* Used to wrap a native `<option>` tag and associate an object with | |
* it that can be bound. It can only be used in conjuction with a | |
* containing `x-select` component | |
* | |
* @class Ember.XOptionComponent | |
* @extends Ember.Component | |
*/ | |
export default Ember.Component.extend({ | |
tagName: 'option', | |
attributeBindings: ['selected', 'name', 'disabled', 'value', 'title'], | |
classNameBindings: [':x-option'], | |
/** | |
* The value associated with this option. When this option is | |
* selected, the `x-select` will fire its action with this | |
* value. | |
* | |
* @property value | |
* @type Object | |
* @default null | |
*/ | |
value: null, | |
/** | |
* Property bound to the `selected` attribute of the native | |
* `<option>` element. It is aware of the containing `x-select`'s | |
* value and will mark itself if it is the same. | |
* | |
* @private | |
* @property selected | |
* @type Boolean | |
*/ | |
selected: Ember.computed('value', 'select.value', 'select.multiple', function() { | |
if (this.get('select.multiple') && isArray(this.get('select.value'))) { | |
let selectValue = Ember.A(this.get('select.value')); | |
return selectValue.contains(this.get('value')); | |
} else { | |
return this.get('value') === this.get('select.value'); | |
} | |
}), | |
/** | |
* Register this x-option with the containing `x-select` | |
* | |
* @override | |
*/ | |
didInsertElement() { | |
this._super.apply(this, arguments); | |
Ember.run.scheduleOnce('afterRender', this, 'registerWithXSelect'); | |
}, | |
registerWithXSelect() { | |
var select = this.nearestOfType(XSelectComponent); | |
Ember.assert("x-option component declared without enclosing x-select", !!select); | |
this.set('select', select); | |
select.registerOption(this); | |
}, | |
/** | |
* Unregister this x-option with its containing x-select. | |
* | |
* @override | |
*/ | |
willDestroyElement: function() { | |
this._super.apply(this, arguments); | |
this.get('select').unregisterOption(this); | |
} | |
}); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Ember from 'ember'; | |
var isArray = Ember.isArray; | |
/** | |
* Wraps a native <select> element so that it can be object and | |
* binding aware. It is used in conjuction with the | |
* `x-option` component to construct select boxes. E.g. | |
* | |
* {{#x-select value="bob" action="selectPerson"}} | |
* {{x-option value="fred"}}Fred Flintstone{{/x-option}} | |
* {{x-option value="bob"}}Bob Newhart{{/x-option}} | |
* {{/x-select}} | |
* | |
* the options are always up to date, so that when the object bound to | |
* `value` changes, the corresponding option becomes selected. | |
* | |
* Whenever the select tag receives a change event, it will fire | |
* `action` | |
* | |
* @class Ember.XSelectComponent | |
* @extends Ember.Component | |
*/ | |
export default Ember.Component.extend({ | |
tagName: "select", | |
classNameBindings: [":x-select"], | |
//FIXME: add 'form' attribute binding back in when https://github.com/tildeio/htmlbars/pull/353#issuecomment-116187095 | |
//is merged. | |
attributeBindings: ['disabled', 'tabindex', 'multiple', 'form', 'name', 'autofocus', 'required', 'size', 'title'], | |
/** | |
* Bound to the `disabled` attribute on the native <select> tag. | |
* | |
* @property disabled | |
* @type Boolean | |
* @default false | |
*/ | |
disabled: false, | |
/** | |
* Bound to the `multiple` attribute on the native <select> tag. | |
* | |
* @property multiple | |
* @type Boolean | |
* @default false | |
*/ | |
multiple: false, | |
/** | |
* Bound to the `tabindex` attribute on the native <select> tag. | |
* | |
* @property tabindex | |
* @type Integer | |
* @ default 0 | |
*/ | |
tabindex: 0, | |
/** | |
* Alias to `value`. | |
* This way we accept `value` or `selection` properties. | |
* | |
* @property selection | |
*/ | |
selection: Ember.computed.alias('value'), | |
/** | |
* Alias to `prompt`. | |
* This way we accept `prompt` or `placeholder` properties. | |
* | |
* @property placeholder | |
*/ | |
placeholder: Ember.computed.alias('prompt'), | |
/** | |
* The collection of options for this select box. When options are | |
* inserted into the dom, they will register themselves with their | |
* containing `x-select`. This is for internal book-keeping only and should | |
* not be changed from outside. | |
* | |
* @private | |
* @property options | |
*/ | |
options: Ember.computed(function() { | |
return Ember.A(); | |
}), | |
/** | |
* When the select DOM event fires on the element, trigger the | |
* component's action with the current value. | |
*/ | |
change() { | |
if (this.get('multiple')) { | |
this._updateValueMultiple(); | |
} else { | |
this._updateValueSingle(); | |
} | |
this.sendAction('action', this.get('value'), this); | |
}, | |
/** | |
* Updates `value` with the object associated with the selected option tag | |
* | |
* @private | |
*/ | |
_updateValueSingle: function(){ | |
var option = this.get('options').find(function(option) { | |
return option.$().is(':selected'); | |
}); | |
if (option) { | |
this.set('value', option.get('value')); | |
} else { | |
this.set('value', null); | |
} | |
}, | |
/** | |
* Updates `value` with an array of objects associated with the selected option tags | |
* | |
* @private | |
*/ | |
_updateValueMultiple: function() { | |
var options = this.get('options').filter(function(option) { | |
return option.$().is(':selected'); | |
}); | |
this.set('value', Ember.A(options).mapBy('value')); | |
}, | |
/** | |
* @override | |
*/ | |
willDestroyElement: function() { | |
this._super.apply(this, arguments); | |
// might be overkill, but make sure options can get gc'd | |
this.get('options').clear(); | |
}, | |
/** | |
* If this is a multi-select, and the value is not an array, that | |
* probably indicates a misconfiguration somewhere, so we error out. | |
* | |
* @private | |
*/ | |
ensureProperType: Ember.on('init', Ember.observer('value', function() { | |
var value = this.get('value'); | |
if (value != null && this.get('multiple') && !isArray(value)) { | |
throw new Error('x-select multiple=true was set, but value "' + value + '" is not enumerable.'); | |
} | |
})), | |
/** | |
* @private | |
*/ | |
registerOption: function(option) { | |
this.get('options').addObject(option); | |
}, | |
/** | |
* @private | |
*/ | |
unregisterOption: function(option) { | |
this.get('options').removeObject(option); | |
} | |
}); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment