How to open a route in a modal dialog in ember.js? - javascript

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

Related

Multiple Router outlets in different templates Angular4

I login using router-outlet tag in main app.component.html and if the login is successful i navigate to home page which is a different component consists of toolbar,side-nav and an area to display my dashboard content.Now in my home page i need another router-outlet where it displays the content upon choosing option in side-nav
my project structure is :
src
--login
----login.component.html
----login.component.ts
----login.component.css
--home-page
dashboard
--dashboard.component.html
--dashboard.component.ts
----home.component.html
----home.component.ts
----home.component.css
--application-details
app-overview
--app-overview.component.html
--app-overview.component.ts
----application.component.html
----application.component.ts
--users
----users.component.html
----users.component.ts
In my app.component.html has the following
<router-outlet></router-outlet>
In login.componnet.ts
upon success this.route.navigate(['/home-page'])
In my app-routing.module.ts
{ path:'', redirectTo:'/login',pathMatch:'full'},
{ path: 'login', component: LoginComponent},
{ path:'/home-page',component:HomePgaeComponent,
children:[
{ path:'',component:DashboardComponent,outlet:'dashboard'},
{ path:'user',component:UsersComponent,outlet:'user'}, ]
},
now as soon as i login based on success condition triggers the page
navigates to dashboard which is inside home page like this
<tool-bar></tool-bar>
<div>
<side-menu></side-menu>
<div class="main-content">
<router-outlet name="dashboard"></router-outlet>
<router-outlet name="user"></router-outlet>
</div>
</div>
here when i click upon the user option from side-nav it appends dashboard
content as well as "user" content.I have other options as well so for the
very first time it loads the landing page perfectly but when i select other
side-nav options all the other content is mixed up. So When i select options
from side-nav that respective content should be loaded in content area of
home page.another scenario is when i navigate to homepage i need to navigate
to another page when i perform some click action in dashboard component.
I have gone through tutorials and there they were passing some ids through
services and i have no idea how to do that. As per my knowledge i know that
passing outlet name into router-outlet will fetch the content of that
component likewise as many router i mention those many multiple routers will
be generated.
here when i click upon the user option from side-nav it appends
dashboard content as well as "user" content
<router-outlet name="dashboard"></router-outlet>
<router-outlet name="user"></router-outlet>
Both are children of same component
{ path:'/home-page',component:HomePgaeComponent,
children:[
{ path:'',component:DashboardComponent,outlet:'dashboard'},
{ path:'user',component:UsersComponent,outlet:'user'}, ]
},
Either you use same router outlet to render both dashboard and user or you have user router outlet inside dashboard and user is child of dashboard.

using Ember-data with JSONApi and opening page in a new tab

I have a page that has pictures (index.js) and when you click a picture, a detail page with bigger version of the picture and its content (pic.js) opens. When I was using hard-coded data, I created a service and put the data in it. By this way, the model hook wasn't skipped when I click a picture. I did it because my links are dynamic {{#link-to}} helper and I saw that model hook gets skipped when you have it. But now, I need to use JSON api to get the data from an URL, when I do it in the index.js there is no problem with displaying it but when I try to open any link in new tab or paste a link in URL bar, model hook doesn't work in pic.js.
//routes/index.js
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return Ember.$.getJSON('My jsonApi Url');
}
});
I read that I need to use ember-data in order to fix it. I created a model "news-list" and put attributes in it. Also I created an adapter and take the code which I call API from index.js and put there.
//adapters/application.js
import JSONAPIAdapter from 'ember-data/adapters/json-api';
import Ember from 'ember';
export default JSONAPIAdapter.extend({
model(params){
return Ember.$.getJSON('My jsonApi Url',params.NewsUrl);
}
});
//templates/index.hbs
{{image-list model=model.Data currentPos=currentPos }}
{{outlet}}
//templates/components/image-list.hbs
{{#each model as |pic|}}
<div>{{#link-to "pic" pic}}
<p class="info">{{pic.Title}}</p><br/>
<img src={{pic.Image}} width="300">
{{/link-to}}</div> {{/each}}
{{yield}}
//routes/pic.js
import Ember from 'ember';
export default Ember.Route.extend({
activate: function() {
this._super(...arguments);
window.scrollTo(0,0);
},
model() {
//return this.store.findAll('news-list');
}
});
//templates/pic.hbs
<p class= "back">{{#link-to 'index'}}Home Page{{/link-to}}</p>
<p class="detail"><img src="{{model.Image}}" width="600" ></p>
<p class="content"><br/><br/>{{model.Content}}</p><br/><br/>
<p class= "back">{{#link-to 'index'}}Home Page{{/link-to}}</p>
{{outlet}}
I tried to use return this.store.findAll('news-list'); in the pic.js but then all I see was a blank page when I click a picture.
I guess there is something I'm missing. I can't use ember-data properly. How can I fix it?

Action not being sent from component in EmberJS

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.

"Ember Simple Auth" invalidateSession from component

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

Render, Partial, View. what should i put in my template?

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.

Categories

Resources