Is there any way to call route action from another router/controller? Let's say I have two routes:
App.RouteOne = Ember.Object.extend({
actions: {
someCommonFunctionality: function() {
// ...
}
}
});
App.RouteTwo = Ember.Object.extend({
actions: {
// Here I want to call someCommonFunctionality function from RouteOne
}
});
Is this somehow possible? I have an AJAX get method that I do not want to repeat in RouteTwo as I have it already in RouteOne
I want execute couple of ember actions synchronously, what is the right way to do this. For example
this.send('closeModal');
this.send('openModal','login'); // run when `closeModal` is totally executed
or how to call action in route without using send
export default Ember.Route.extend({
actions:{
openModal: function () {
//how to execute like this.closeModal(); without .send
... logic...
});
closeModal: function () {
... logic...
});
}
});
Perhaps you could move the action logic to other functions on the route i.e.
export default Ember.Route.extend({
openModal: function() {
...logic...
},
closeModal: function() {
...logic...
},
actions:{
openModal: function () {
this.closeModal(); // Ensure other modals are closed.
this.openModal();
});
closeModal: function () {
this.closeModal();
});
}
});
I'm writing a Mixin to handle when user clicks outside of a view/component.
This is the mixin:
App.ClickElsewhereMixin = Ember.Mixin.create({
onClickElsewhere: Ember.K,
didRender: function() {
this._super.apply(this, arguments);
return $(document).on('click', this.get('onClickElsewhere'));
},
willDestroyElement: function() {
this._super.apply(this, arguments);
$(document).off('click', this.get('onClickElsewhere'));
},
});
I use it in my component:
onClickElsewhere: function() {
this.send('exitEditMode');
},
But when I run it, I get:
TypeError: this.send is not a function
How can I keep the this context?
Solution:
just to make it easier for the reader, here the working Mixin:
App.ClickElsewhereMixin = Ember.Mixin.create({
onClickElsewhere: Ember.K,
setupListener: Ember.on('didRender', function() {
// Set an event that will be fired when user clicks outside of the component/view
return $(document).on('click', $.proxy(this.get('onClickElsewhere'), this));
}),
removeListener: Ember.on('willDestroyElement', function() {
// Clean the previously defined event to keep events stack clean
return $(document).off('click', $.proxy(this.get('onClickElsewhere'), this));
}),
});
The current answer doesn't check whether the click was actually outside of the element – a click on the component will also trigger the callback.
Here's an updated version:
export default Ember.Mixin.create({
onOutsideClick: Ember.K,
handleOutsideClick: function(event) {
let $element = this.$();
let $target = $(event.target);
if (!$target.closest($element).length) {
this.onOutsideClick();
}
},
setupOutsideClickListener: Ember.on('didInsertElement', function() {
let clickHandler = this.get('handleOutsideClick').bind(this);
return Ember.$(document).on('click', clickHandler);
}),
removeOutsideClickListener: Ember.on('willDestroyElement', function() {
let clickHandler = this.get('handleOutsideClick').bind(this);
return Ember.$(document).off('click', clickHandler);
})
});
Greg answer have a mistake, that makes removing the clickHandler event not working. Which means that your clickevent will fire even if you destroy the component.
Here is proper version
import Ember from 'ember';
export default Ember.Mixin.create({
onOutsideClick: Ember.K,
handleOutsideClick: function(event) {
let $element = this.$();
let $target = $(event.target);
if (!$target.closest($element).length) {
this.onOutsideClick();
}
},
setupOutsideClickListener: Ember.on('didInsertElement', function() {
let clickHandler = this.get('handleOutsideClick').bind(this);
return Ember.$(document).on('click', clickHandler);
}),
removeOutsideClickListener: Ember.on('willDestroyElement', function() {
let clickHandler = this.get('handleOutsideClick').bind(this);
return Ember.$(document).off('click', Ember.run.cancel(this, clickHandler));
})
});
The ember way of doing it is Ember.run.bind. This takes care of binding and the run loop.
App.ClickElsewhereMixin = Ember.Mixin.create({
onClickElsewhere: Ember.K,
setupListener: Ember.on('didRender', function() {
this.set('clickHandler', Ember.run.bind(this, this.onClickElsewhere));
Ember.$(document).click(this.get('clickHandler'));
}),
removeListener: Ember.on('willDestroyElement', function() {
Ember.$(document).off('click', this.get('clickHandler'));
}),
});
You have two options:
Use a closure
Use bind
Closure
App.ClickElsewhereMixin = Ember.Mixin.create({
onClickElsewhere: Ember.K,
didRender: function() {
this._super.apply(this, arguments);
return $(document).on('click', function(this){ return this.get('onClickElsewhere'); }(this));
},
willDestroyElement: function() {
this._super.apply(this, arguments);
$(document).off('click', function(this){ return this.get('onClickElsewhere'); }(this));
},
});
Bind
App.ClickElsewhereMixin = Ember.Mixin.create({
onClickElsewhere: Ember.K,
didRender: function() {
this._super.apply(this, arguments);
return $(document).on('click', this.get('onClickElsewhere').bind(this));
},
willDestroyElement: function() {
this._super.apply(this, arguments);
$(document).off('click', this.get('onClickElsewhere').bind(this));
},
});
However, not all browsers support bind yet.
Also, I think you need to use sendAction instead of send in the component (http://guides.emberjs.com/v1.10.0/components/sending-actions-from-components-to-your-application/)
Edit:
jQuery.proxy uses call/apply underneath the covers. See this post for a discussion of call/apply vs bind.
You can use the lib ember-click-outside. Worked for me.
Given the following code, how can the route call it's doSomething action?
export default Ember.Route.extend({
setupController: function(controller, model) {
// call the doSomething action
},
actions: {
doSomething: function() { ... }
}
}
You can use Transition object which is passed do beforeModel/model/afterModel hook.
App.IndexRoute = Ember.Route.extend({
actions: {
doSomething() {
console.log('doSomethingInvoked');
}
},
beforeModel(transition) {
transition.send('doSomething');
},
model(params, transition) {
transition.send('doSomething');
},
afterModel(model, transition) {
transition.send('doSomething');
}
});
Working demo.
I have code such as that shown below, and I'm just wondering how I can trigger another event within the route's events. Thoughts?
App.MyRoute = Ember.Route.extend({
events: {
eventOne: function() {
// do something
},
eventTwo: function() {
// how do I call eventOne() here?
},
}
});
You can just call events.eventOne() using this as the context:
App.IndexRoute = Ember.Route.extend({
events: {
eventOne: function() {
console.log('You got me!');
},
eventTwo: function() {
this.events.eventOne();
},
}
});