Controller's computed property invoke (depends on checked property) in ember.js - javascript

There is an example in documetation. The code is here.
The documentation talks that isCompleted controller's computed property will be called with argument wich value is either true or false depends on checked input property's value.
How does controller automatically knows that is checked property of input is changed? I mean it's so unobvious that controller's cumputed property will be called when checked input property's state changes. How it works? Where the documentation describes this behavior?
Big thanks.

The controller doesn't know, the input helper binds the checkbox to the passed in argument checked.
{{input type="checkbox" checked=isCompleted class="toggle"}}
http://emberjs.com/guides/templates/input-helpers/
http://emberjs.com/api/classes/Ember.Checkbox.html
Ember.Checkbox = Ember.View.extend({
classNames: ['ember-checkbox'],
tagName: 'input',
attributeBindings: ['type', 'checked', 'indeterminate', 'disabled', 'tabindex', 'name'],
type: "checkbox",
checked: false,
disabled: false,
indeterminate: false,
init: function() {
this._super();
this.on("change", this, this._updateElementValue);
},
didInsertElement: function() {
this._super();
this.get('element').indeterminate = !!this.get('indeterminate');
},
_updateElementValue: function() {
set(this, 'checked', this.$().prop('checked'));
}
});

Related

(Re)rendering Backbone view in change event handler does not work

I'm having two form elements, both 2-way-databinded via backbone.stickit.
The second form element (#input) is just cosmetics - there for showing it's actually working.
The idea is that my View gets (re)rendered,every time the option inside the dropdown (#select) menu gets changed.
I'm trying to achieve that by catching the the 'changed' event of #select and call this.render() to (re)render the view.
Apparently that doesn't work. The selected option doesn't get saved back into the model and I fail to understand why.
I'm not looking for a solution, rather than an explanation, why the following code doesn't work. The solution (as in: works for me) is part of the fiddle - commented out.
HTML:
<script type="text/template" id="tpl">
<h1>Hello <%= select %></h1>
<select id="select">
</select>
<p>Select:
<%= select %>
</p>
<hr>
<input type="text" id="input">
<p>Input:
<%= input %>
</p>
</script>
<div id="ctr"></div>
JavaScript:
Foo = Backbone.Model.extend({
defaults: {
select: "",
input: "",
}
});
FooView = Backbone.View.extend({
el: '#ctr',
template: _.template($('#tpl').html()),
initialize() {
this.model.bind('change', function() {
console.log("model change:");
console.log(this.model.get('select'));
console.log(this.model.get('input'));
}, this);
//this.model.bind('change:select', function() { this.render(); }, this); // <--------------------- WORKS
},
render: function() {
this.$el.html(this.template(this.model.toJSON()));
this.stickit();
return this;
},
events: {
'change #select': function(ev) {
console.log('change event triggered:');
console.log(this.model.get('select'));
console.log(this.model.get('input'));
this.render(); // <--------------------- DOES NOT WORK - WHY?
},
/* 'click #render': function(ev) {
console.log('render event triggered:');
console.log(this.model.get('select'));
console.log(this.model.get('input'));
this.render();
} */
},
bindings: {
'#input': 'input',
'#select': {
observe: 'select',
selectOptions: {
collection: function() {
return [{
value: '1',
label: 'Foo'
}, {
value: '2',
label: 'Bar'
}, {
value: '3',
label: 'Blub'
}]
}
}
},
},
});
new FooView({
model: new Foo()
}).render();
https://jsfiddle.net/r7vL9u07/9/
The reason it does not work to call this.render() from within your change #select event handler is because you are disrupting the two-way data binding that Backbone.stickit is providing you. The flow goes something like the following:
User changes the value of '#select'.
Your change #select handler fires and calls this.render().
render repopulates #ctr with a new select menu with no selected option.
Backbone.stickit responds to the change to #select.
Backbone.stickit tries to obtain the value of #select, but since it contains no selected option the value is undefined.
Backbone.sticket sets the model's select attribute to undefined.
The reason it works if you move the this.render() call to within the model's change:select handler is because Backbone.stickit is able to correctly update the model without the DOM changing before it gets the chance.

Getting an error even when checkbox is checked

From all the examples I found, using is(':checked') should return true if checkbox is checked, and false if not. In my case it returns false on both situations. What is my mistake?
{
xtype: 'checkbox',
boxLabel: 'Show message',
id: 'mainBox',
handler: function() {
alert($(this).is(':checked'));
}
In accordance to the ExtJS documentation, I would try this:
{
xtype: 'checkbox',
boxLabel: 'Show message',
id: 'mainBox',
handler: function (field , value) {
alert(value);
}
}
Because this inside a extjs event handler does not refer to the dom element instead this will refer to a extjs checkbox object. jQuery won't be able to find out the target element using the extjs object reference. Instead you have the getValue() method of checkbox which will return the checked state value, so
Try
{
xtype: 'checkbox',
boxLabel: 'Show message',
id: 'mainBox',
handler: function (el) {
alert(el.getValue());
}
}
As you can read in the jQuery documentation, the .is('...') function returns an jQuery object.
If you want some kind of a boolean as return value, you can try the following code:
alert($(this).is(':checked').length > 0);
But for a checkbox element, using the 'checked' property should work too:
alert(this.checked);
You can even try this if you want to use jQuery:
alert($(this).attr('checked') === 'checked');

How to in-place edit boolean value with x-editable

I want to display a boolean value on a page (actually it'll be cells in a table), and it has to be editable. Furthermore, it's not a checkbox, but I spell out "false" and "true". We use bootstrap 3, and latest knockout. I decided to use x-editable Bootstrap 3 build. I also use a knockout custom binding: https://github.com/brianchance/knockout-x-editable.
I figured that to implement this I need to configure x-editable to be in popup mode, and select type. I also supply the selections ("true" and "false" only in this case) in a parameter. Almost everything is fine and dandy, except that the in-place dialog doesn't display the current value when it pops up. How can I fix that? I tried 'defaultValue' parameter, but it didn't help.
Here is the fiddle:
http://jsfiddle.net/csabatoth/7ybVh/4/
<span data-bind="editable: value,
editableOptions: { mode: 'popup', type: 'select',
source: '[{ value: 0, text: "false" },
{ value: 1, text: "true" }]' }">
</span>
simple model:
function ViewModel() {
var self = this;
self.value = ko.observable(false);
}
The problem is that you have true and false Boolean values in your observable but x-editable uses the 0 and 1 values to represent the "true" and "false" selection.
This causes two problems:
when initialized x-editable does not know that "false" means 0 so no default value selected
if you select anything in your pop-up editor your value observable will contain the "0" and "1" strings and not the false and true Boolean values...
You can solve both problems with intoroducing a computed property which translates between the Boolean and numerical values:
self.computed = ko.computed({
read: function() { return self.value() ? 1 : 0 },
write: function(newValue) { self.value(newValue == '1') }
});
And you need to use this property in your editable binding:
<span data-bind="editable: computed,
editableOptions: { mode: 'popup', type: 'select',
source: '[{ value: 0, text: "false" },
{ value: 1, text: "true" }]' }">
</span>
Demo JSFiddle.

Knockout js observable arrays and checkbox, checked bind fail

I'm trying to figure out why the text entry field is not active when the checkbox changes?
<form data-bind="foreach: editables">
<input type="checkbox" name="edit" data-bind=" checked: active" />
<input type="text" name="edit" data-bind="value: name, disable: !active" />
<br/>
</form>
var viewModel = function () {
this.editables = ko.observableArray(
[{
active: true,
name: "mi"
}, {
active: false,
name: "yo"
}, {
active: true,
name: "cel"
}]);
};
ko.applyBindings(new viewModel());
http://jsfiddle.net/legolito/2FAJN/2/
I hope that someone can helpme. (english isn't my native language, so i'm sorry if something is bad with my grammar )
Have you considered making the active property an observable?
http://jsfiddle.net/tzG3t/
var viewModel = function () {
this.editables = ko.observableArray(
[{
active: ko.observable(true),
name: "mi"
}, {
active: ko.observable(false),
name: "yo"
}, {
active: ko.observable(true),
name: "cel"
}]);
};
ko.applyBindings(new viewModel());
That because you are not using ko.observable in ko.observableArray
See the knockout documentation on observableArrays
Key point: An observableArray tracks which objects are in the array, not the state of those objects
Simply putting an object into an observableArray doesn’t make all of
that object’s properties themselves observable. Of course, you can
make those properties observable if you wish, but that’s an
independent choice. An observableArray just tracks which objects it
holds, and notifies listeners when objects are added or removed.
So make it observable and problem solved.
Fiddle: http://jsfiddle.net/2FAJN/4/

get checkbox value without using Ext.getCmp

I am trying to get value of this checkbox
Ext.define('myRoot.myExtApp.myForm', {
extend: 'Ext.form.Panel',
layout: {
type: 'vbox',
align: 'stretch'
},
scope: this,
constructor: function() {
this.callParent(arguments);
this.myFieldSet = Ext.create('Ext.form.FieldSet', {
scope: this,
columnWidth: 0.5,
collapsible: false,
defaultType: 'textfield',
layout: {
type: 'hbox', align: 'stretch'
}
});
this.mySecondForm = Ext.create('myRoot.myExtApp.myForm2', {
scope: this,
listener: this,
margin: '1 3 0 0'
});
this.myCheckBox = Ext.create('Ext.form.Checkbox', {
scope: this,
//id: 'myCheckBox',
boxLabel: 'Active',
name: 'Active',
checked: true,
horizontal: true
});
this.myFieldSet.add(this.mySecondForm);
this.myFieldSet.add(this.myCheckBox);
this.add(this.myFieldSet);
}
});
As you can see I have another form
Ext.define('myRoot.myExtApp.myForm2', {
where I have a handler, that should get the value of the checkbox from "myForm"
How can I get the value of my checkbox from Form2 without using Ext.getCmp? I know I can get the value of the checkbox if I do
Ext.getCmp('myCheckBox').getValue();
but using
this.myCheckBox.getValue();
gives me undefined error.
UPDATE - with Wared suggestion I tried this inside myForm2
this.temp=Ext.create('myRoot.myExtApp.myForm'), {});
var tempV = this.temp.myCheckBox.getValue();
I was able to get the value but I get the same true value even if I uncheck the box
I assume you worry about performance loss due to excessive use of component queries. A nice trick to minimize component queries could be to define a new method inside a closure in order to cache the result of the first getCmp call. Wrapping the definition of the method inside a closure allows to avoid using global scope or a useless class property.
getMyCmp: function (cmp) {
// "cmp" does not exist outside this function
return function () {
return cmp = cmp || Ext.getCmp('#myCmp');
};
}()
One solution could be :
myRoot.myExtApp.myForm.myCheckBox.getValue();
Beware, wrong answer. See comments below for a valid solution.

Categories