Trying to execute this code within a component's template
// components/my-component.js
{{#if session.isAuthenticated}}
<a {{action 'invalidateSession'}}>Sign out</a>
{{else}}
{{#link-to 'signin'}}Sign in{{/link-to}}
{{/if}}
However, when clicking "Sign out" button I get this error
Error: <...#component:my-component::ember381> had no action handler for: invalidateSession
How do I make "invalidateSession" available from a component?
You can just implement your own invalidateSession action:
actions: {
invalidateSession: function() {
this.get('session').invalidate();
}
}
or simply forward the action from the component to the route:
{{my-component invalidateSession='invalidateSession'}}
You need to add the Simple Auth ApplicationRouteMixin to your ApplicationRoute. For example if you are using ES6 modules do
import ApplicationRouteMixin from 'simple-auth/mixins/application-route-mixin';
ApplicationRoute = Ember.Route.extend ApplicationRouteMixin,
The action should bubble up to the application route, where it will be handled.
See the documentation here
Related
{{#each alarms as |alarm|}}
{{if alarm.isEditing}}
{{#modal-dialog translucentOverlay=true close="cancelAlarmEdit"}}
//this works down here
<button type="btn btn-danger" {{action 'cancelAlarmEdit' alarm}}</button>
{{/modal-dialog}}
{{else}}
{{/if}}
{{/each}
Is there a way to pass a model into cancelAlarmEdit from the close tag above? I had trouble finding relevant info on it from https://github.com/yapplabs/ember-modal-dialog .
I'm pretty sure this should work:
{{#modal-dialog close=(action 'cancelAlarmEdit' alarm)}}
Actually the {{action}} helper is pretty similar to Javascripts bind.
I don't see such feature neither in docs, nor in the source code of this addon. You may try to create a new component, based on this addon's:
// app/components/modal-dialog.js
import ModalDialog from 'ember-modal-dialog/components/modal-dialog';
export default ModalDialog.extend({
actions: {
close() {
this.sendAction('close', this.get('closeParam'));
}
}
});
In template your should be able to pass closeParam attribute.
And if you will not succeed in extending, it's not that hard to write your own modal component.
We have a requirement of opening a modal dialog containing a route or a component. We are looking for some modal components, and saw ember-bootstrap's modal is useful.
So,
How can we open any route as a modal dialog ? (If parent route decides a route to be open in a modal, the child route should be open in modal.)
Can we create a service, to pop up a modal dialog? Such as: ModalDialogService.popup(title, bodyComponent, commitHandler, cancelHandler); or ModalDialogService.popup(title, routeName, commitHandler, cancelHandler); And how can we do this without violating the Data Down Action Up principle?
Is there any guide, document, tutorial or npm package for implementing modals in ember.js?
UPDATED:
What I need is to open any of the current routes in a modal. For example, in a given route hierarchy:
-module1
|-module1.query
|-module1.add
|-module1.update
|-module1.delete
Currently module1.query has transitions to others. But I want to give an option to the module developers to open any of the add, update, delete routes in a modal. So that query route doesn't lose its state, when an add operation finished.
Also we have some services used by components. At some conditions, services need to display a modal that has a component.
You should be able to use a service and component similar to one below to achieve what you want.
Have a look at the twiddle for a demo of how this works exactly, and the code below for quick reference
Your route template could look something like this.
// templates/hasmodal.hbs
{{#bs-modal}}
Modal Content
{{/bs-modal}}
Your route hooks, with service injected
// routes/hasmodal.js
export default Ember.Route.extend({
modalNavigation: Ember.inject.service(),
activate(){
console.log('openingModal')
this.get('modalNavigation').openModal()
},
deactivate(){
console.log('closingModal')
this.get('modalNavigation').openModal()
},
actions: {
onClose(){
console.log('we want to close route')
}
}
})
Your bs-modal or relevant component
//components/bs-modal.js
export default Ember.Component.extend({
modalNavigation: Ember.inject.service(),
isOpen: Ember.computed.alias('modalNavigation.modalOpen'),
classNameBindings: ['isOpen:modalDialog:notOpen'],
actions: {
close(){
this.get('modalNavigation').closeModal()
}
}
})
The bs-modal component template
// templates/components/bs-modal
<div>
{{yield}}
</div>
<button class='close' {{action 'close'}}>Close Me</button>
Your Modal Service to manage state
// services/modal-navigation.js
export default Ember.Service.extend({
modalOpen: false,
openModal(){
this.set('modalOpen',true)
},
closeModal(){
this.set('modalOpen',false)
}
})
UPDATE:
updated twiddle
It basically nests routes that contain a modal underneath a route you want to preserve the state of and show behind the modal.
// router.js [truncated]
Router.map(function() {
this.route('module1',function(){
this.route('query',function(){
this.route('add')
this.route('update', { path: '/update/:item_id' })
this.route('delete', { path: '/delete/:item_id' })
})
})
// templates/modules1/query.hbs
Queried List {{link-to 'add item' 'module1.query.add'}}<br/>
<ul>
{{#each model as |item|}}
<li>
{{item.id}}-{{item.title}}
{{link-to 'u' 'module1.query.update' item}}
{{link-to 'd' 'module1.query.delete' item}}
</li>
{{/each}}
</ul>
{{outlet}}
// templates/module1/query/add.hbs
{{#modal-component isOpen=true onClose=(action "routeClosed")}}
<div>
Title:{{input value=model.title}}
</div>
<button {{action 'save'}}>Save</button>
{{/modal-component}}
Where all the other sub components follow the same modal wrapper principle
When I close a bootstrap modal, it doesn't send the action it should (in application js:)
application.hbs:
<li><a {{action "showSignInModal"}}>Sign In</a></li>
{{outlet}}
{{outlet 'modal'}}
bootstrap-modal.js:
this.$('.modal').modal().on('hidden.bs.modal', function() {
alert("Closed");
this.sendAction('removeModal');
}.bind(this));
routes/application.js:
export default Ember.Route.extend({
actions: {
showSignInModal: function() {
this.render('components.signin-modal', {
into: 'application',
outlet: 'modal'
});
},
removeModal: function(){
alert("Working")
}
//...
}
})
signin-modal.hbs:
{{#bootstrap-modal title="Sign In" ok='signin' okText="Signin"}}
<p>
Please sign in. Thanks!
</p>
{{/bootstrap-modal}}
The "closed" alert shows, but the "working" alert doesn't.
(The signin modal is a component, with no actions defined, and is just a bootstrap-modal)
You are not passing your action name properly.
You need to be aware that the sendAction method will fail silently if it can't find the action name.
Make sure inside your template that contains the modal component, you pass a property with the action name you want to call:
{{#bootstrap-modal title="Sign In" ok='signin' okText="Signin" removeModal="removeModal"}}
You can read more about Passing Actions to Components
Actions won't propagate like event bubbing
Wrap your bootstrap modal into a component and give it the removeModal action from the signin-modal to call.
I'm working through Ryan LaBouve's YouTube tutorial on building the TodoMVC app with Ember CLI. I'm about half way through, now adding a conditional within the template. When a (todo list) item is double-clicked, it is supposed to trigger a function editTodo that sets a property "isEditing" to true and replaces the text with an input box.
The doubleClick function is not working at all. It throws the following error in the console:
Uncaught Error: Nothing handled the action 'editTodo'. If you did handle the action, this error can be caused by returning true from an action handler in a controller, causing the action to bubble.
This is the relevant template section (todos.hbs):
<section id="main">
<ul id="todo-list">
{{#each todo in model itemComtroller="todo"}}
<li {{bind-attr class="todo.isCompleted:completed todo.isEditing:editing"}}>
{{#if todo.isEditing}}
<input class="edit">
{{else}}
{{input type="checkbox" class="toggle" checked=todo.isCompleted}}
<label {{action "editTodo" on="doubleClick"}}>{{todo.title}}</label><button class="destroy"></button>
{{/if}}
</li>
{{/each}}
</ul>
<input type="checkbox" id="toggle-all">
</section>
Here is the controller with the "editTodo" function (todo.js):
import Ember from 'ember';
export default Ember.ObjectController.extend({
actions: {
editTodo: function() {
this.set('isEditing', true);
}
},
isEditing: false,
isCompleted: function(key, value) {
var model = this.get('model');
if (value === undefined ) {
return model.get('isCompleted');
} else {
model.set('isCompleted', value);
model.save();
return value;
}
}.property('model.isCompleted')
});
I've cross-referenced my code with the video and the associated Github repo and still can't find the cause of the problem. There are also related issues on SO, but I've not seen one quite like this. Obviously I am new to Ember.js and can use all the help I can get.
THANKS!
It seems that you've run into a bug that was introduced in Ember 1.13.4. I'm not sure what it is, but it has to do with using an item controller and having an action in the loop. For now, you can downgrade to Ember 1.13.3 or lower to fix the issue. I will file a bug report so that this can be fixed in later versions of Ember.
Long term you won't be writing code like this. Item controllers have been completely removed in Ember 2.0, so you'll likely switch to using components for this type of situation when using Ember 2.0. For now you can practice using Ember 1.13.3.
Almost forgot:
Code that works in 1.13.3
Same code broken in 1.13.4
EDIT: Link to GitHub issue
EDIT2: It seems that some behavior has changed in Ember (possibly another bug?) between 1.12.0 and 1.13.0. For some reason the actions are no longer being caught in the item controller and instead are being sent directly to the route controller. I'm not 100% sure why that is, but as a fix you can either downgrade to Ember 1.12 or move your editTodo action to your todos controller instead.
EDIT3: Link to second Github issue
EDIT4: As suggested in the second bug ticket, you can also change the target of the action:
<label {{action "editTodo" on="doubleClick" target="todo"}}>{{todo.title}}</label>
I have an application where i wish to create a user profile widget. The widget will sit in the navbar in the application template. the widget will look like a login button that pops up a modal login dialog or a dropdown menu that contains links to various user related functions/routes.
the logic for the widget is so far this:
{{#if 'user.loggedIn'}}
<span class="glyphicon glyphicon-user"/> {{user.username}}
<ul class="dropdown-menu">
<li>{{#link-to "profile" user}}Profile{{/link-to}}</li>
<li>{{#link-to "logoff" user}}Logout{{/link-to}}</li>
</ul>
{{else}}
<button class="btn btn-primary navbar-btn" data-target="#loginModal" data-toggle="modal">Login</button>
{{/if}}
I wish to have a controller handle the login functions and calling the modal prompt:
App.UserController = Em.ObjectController.extend({
loggedIn: Em.computed.readOnly('model.loggedIn'),
username: '',
password: '',
showLoginModal: function(){
Em.$("#loginModal").modal();
},
hideLoginModal: function() {
Em.$("#loginModal").modal('hide');
},
login: function() {
var username = this.get('username'),
success = true; //attempt a login
console.log('logging in as' + username);
if(success) {
this.send('hideLoginModal');
this.set('user.loggedIn', true);
}
return false;
}
});
So my question is, what is the best way to get this component/view/partial into the application template using the UserController for the widget?
I'm very new to ember so please be nice :).
I would use a component for the view, and handle the login logic in the ApplicationController and the UserModel.
But actually, there are multiple ways to solve that problem! U could also do it directly in the applicationTemplate.
But: U should not use a normal view or partitial! Mostly u should use a component instead!
The render helper IS an option, if u need the View/Controller pattern, and if its not clearly seperated!
Generall:
If u can seperate it, you should. And then u should use a component.