I am using Ember and when I type in text box the binded property on the controller is automatically as I type, I would like to know if there is way to change this only update the property on the blur event?
You can bind a temporary property to your input's value and use the focus-out event to update the "real" property:
{{input value=tempValue focus-out="updateValue"}}
actions: {
updateValue() {
this.set('realValue', this.get('tempValue'));
}
}
Related
I am using ember-font-awesome,
https://github.com/martndemus/ember-font-awesome
When I try to bind a click action handler on the component (see code below) the action is never get triggered,
Inside my component
{{fa-icon "times" (action "paramRemove" param on="click")}}
How can I bind a action to a component without re-open the component?
You need to define click attribute value using action helper.
Reference - https://github.com/martndemus/ember-font-awesome#actions
{{fa-icon "times" click=(action "paramRemove" param)}}
With Ember 2.0, there is a deprecation for modifying properties in a component's didInsertElement hook. The following scenario exposes a problem when trying to integrate other third party libraries, in this case d3.
I have an ember component that wraps a d3 visualization, having as tagName: svg. There are two properties which are passed down from the parent into this component, the width and height. There are observers on these two properties within the d3 component to update the visualization to make it responsive to changes in the window size.
The problem arises in the parent component. I am currently binding to the window resize event, running Ember.run and a callback which sets the windowSize property in the component. I have two computed properties which depend on windowSize, the width and height which are computed according to the DOM's width and height (which are dynamic thanks to columns in bootstrap). Hence, the computed properties look like:
halfWidth: Ember.computed('windowSize', function() {
return $(this.get('halfSelector')).first().width();
})
However, when passing the computed property to the d3 component as {{d3-component width=halfWidth}} there is no default. This computed property is only computed when the resize event on the window is fired. If I resize the window the d3 component updates correctly with the new width.
didInsertElement() {
$(window).on('resize', () => {
Ember.run(() => {
this.set('windowSize', $(window).width());
});
});
// In order have the computed properties to have defaults, one could do
// $(window).trigger('resize')
// However this line is responsible for raising the deprecation notice.
}
How do I give the computed property a default value which depends on a width of a DOM node after the component has been inserted into the DOM?
In order to get rid of the deprecation, I changed the definition of the didInsertElement to the following:
didInsertElement() {
let onWindowResize = () => {
this.set('windowSize', $(window).width());
};
$(window).on('resize', () => { Ember.run(onWindowResize); });
Ember.run.scheduleOnce('afterRender', onWindowResize);
}
I got inspiration from https://github.com/emberjs/ember.js/issues/11493. The problem was also referenced as Forcing layout calculations to use in further positioning. In order to avoid the deprecation of setting properties in the didInsertElement hook, one uses the afterRender queue to schedule the change.
A few months back ember.js changed the scoping of "actions" that get invoked from something like a button click. For example, in the below handlebars template if I click "save"
<button type="submit" {{action updateModel model}}>Save</button>
It bubbles up to the actions on my controller like so
actions: {
updateModel: function(model) {
var name = model.get('name');
//if I want to hit a mixin or instance method
//I am forced to use "send" but how can I send
//state to this method? or is this even the way
//ember wants you to "reuse" code from within
//an action?
}
}
The problem is, if I have a complex action and I want to share code between controllers. What is the "correct" way to share even a simple "validate" like method when I'm stuck inside an "action" like this?
I'm facing a big problem that it's taking a lot of time to be fixed because I don't know the cause and how to fix it. The problem is really simple: I have an example QML component defined as:
Rectangle {
id: rect
property bool test: myclass.testproperty
Rectangle {
width: 50
height: 50
visible: parent.test
}
}
and I connected a MouseArea onClicked signal to do this:
test = !test
so I switch the value of the boolean variable. To push the value from C++ to QML and from QML to C++ Q_PROPERTY with READ, WRITE and NOTIFY signals, I used this
Binding {
target: myclass
property: "testproperty"
value: rect.test
}
everything works fine until I click on the mouseArea and so I push the changes via the binding. After that, every time I try to set a new property value from C++ I don't see any change in QML, like if the binding is destroyed. But if I try to click on the MouseArea I still call the setTestProperty method of the C++ class. Basically, it goes out of sync the C++ -> QML way. Why? I can't find the problem, the signal is emitted because QSignalSpy gives me 1 as count of emitted times after using
emit this->testPropertyChanged(newvalue)
EDIT
here an example: basically here we're using a QString property with the same exact signals. The only thing that changes is that instead of using a Rectangle QML element and binding to a own property, I'm using a TextInput element
TextInput {
id: mytext
text: myclass.testproperty
}
Binding {
target: myclass
property: "testproperty"
value: mytext.text
}
There is no problem here. It is a standard QML bindings behaviour. When you change some QML Widget's property in JavaScript code, then all declarative bindings to it will be terminated. It is your choice to use declarative binding or update values manually in JS code of event handlers.
EDIT
Rectangle {
id: rect
// Establishing initial value for 'test' property via QML binding
property bool test: myclass.testproperty
// Manual update of 'test' property when binding will be broken
Connections {
target: myclass
onTestpropertyChanged: {
rect.test = xxx
}
}
}
It seems like if you want to animate a transition between states using the new Ember.js router and outlets, you're out of luck, since the previous content of an outlet will be destroyed before you have a chance to animate it. In cases where you can completely animate one view out before transitioning to the new state, there's no problem. It's only the case where both old and new views need to be visible that's problematic.
It looks like some of the functionality needed to animate both the previous outlet content and the new was added in this commit, but I'm not sure I understand how to use it.
There's also been some discussion about using extra transitional routes/states to explicitly model the "in-between" states that animations can represent (here and here), but I'm not sure if it's currently possible to match this approach up with outletted controllers and views.
This is similar to How *not* to destroy View when exiting a route in Ember.js, but I'm not sure overriding the outlet helper is a good solution.
Any ideas?
I am currently overriding didInsertElement and willDestroyElement in some of my view classes to support animations. didInsertElement immediately hides the element and then animates it into view. willDestroyElement clones the element and animates it out of view.
didInsertElement: function ()
{
this.$().slideUp(0);
this.$().slideDown(250, "easeInOutQuad");
},
willDestroyElement: function ()
{
var clone = this.$().clone();
this.$().replaceWith(clone);
clone.slideUp(250, "easeInOutQuad");
}
Personally, I don't want to start wrapping my outlets in superfluous ContainerViews just to support animations.
You should check this out: https://github.com/billysbilling/ember-animated-outlet.
Then you can do this in your Handlebars templates:
{{animatedOutlet name="main"}}
And transition from within a route like this:
App.ApplicationRoute = Ember.Route.extend({
showInvoice: function(invoice) {
this.transitionToAnimated('invoices.show', {main: 'slideLeft'}, invoice);
}
});