可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
How do you create a modal popup with the latest version of ember.js? Every single example I've found uses connectOutlet, which was deprecated a while ago, and the fact that I'm new to ember doesnt help.
I already have a named outlet in my application template, but how do I render my modal popup view to this outlet from a controller event? or should I use a route event?
回答1:
Adam Hawkins just published an excellent post on this topic, you can find it here: http://hawkins.io/2013/06/ember-and-bootstrap-modals/
To summarize:
- Include
{{outlet modal}}
in application.hbs
- Render into the outlet from your router by using events
- Animation triggered by the view's
didInsertElement
hook and on it's close
action
- Modal's
close
action should target the view, which waits for animation to complete before sending close
event to the router
From Adam's jsfiddle:
App.ApplicationRoute = Ember.Route.extend({
events: {
open: function() {
this.render('modal', { into: 'application', outlet: 'modal' });
},
close: function() {
this.render('nothing', { into: 'application', outlet: 'modal' });
},
save: function() {
alert('actions work like normal!');
}
}
});
App.ModalView = Ember.View.extend({
didInsertElement: function() {
this.$('.modal, .modal-backdrop').addClass('in');
},
layoutName: 'modal_layout',
close: function() {
var view = this;
// use one of: transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd
// events so the handler is only fired once in your browser
this.$('.modal').one("transitionend", function(ev) {
view.controller.send('close');
});
this.$('.modal, .modal-backdrop').removeClass('in');
}
});
回答2:
When using Bootstrap 3.0 and final Ember 1.0, I couldn't get this code working.
I rewrote it a bit (in coffeescript, layout and template handlebars are already precompiled to js with Grunt's emberTemplates)
app.coffee
App.ApplicationRoute = Ember.Route.extend({
actions:
open: ->
console.debug('open action triggered')
@render('ContactModal', {into: 'profile', outlet: 'contactModal'})
close: ->
@render('nothing', {into: 'profile', outlet: 'contactModal'})
save: ->
alert('Send the message to person')
})
modal_view.coffee
App.ModalView = Ember.View.extend({
didInsertElement: ->
@$('.modal').modal('show')
view = @
@$('.modal').on("hidden.bs.modal", (ev)->
view.controller.send('close')
return
)
layout: Ember.TEMPLATES['modal_layout']
template: Ember.TEMPLATES['modal']
actions:
close: ->
@$('.modal').modal('hide')
return
})
This way clicking outside the modal also closes it properly, since removing the template from outlet is done on hiding the modal.
modal.handlebars:
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" {{action close target="view"}}>×</button>
<h3 class="modal-title">Contact</h3>
</div>
<div class="modal-body">
<p>Here will go the contact form and contact template picker</p>
</div>
<div class="modal-footer">
<a href="#" class="btn btn-default" {{action close target="view"}}>Close</a>
<a href="#" class="btn btn-primary" {{action save}}>Send</a>
</div>
</div>
modal_layout.handlebars
<div class="modal fade" role="dialog">{{yield}}<div>
I also put togheter a jsfiddle: http://jsfiddle.net/bG4F8/5/
Have fun :)
回答3:
Thank you for sharing your code Mike & Damian! Here is how I used it:
Router:
App.Router.map ()->
@resource 'posts', ->
@resource 'post', path:':post_id', ->
@route 'modal'
Route:
App.PostModalRoute = Em.Route.extend
setupController: (model, controller) ->
@controllerFor('post.modal').set 'content', @modelFor('post')
@render 'posts/modal', into: 'application', outlet: 'modal'
# Note: you need outlet named 'modal' in application template
View:
App.ModalView = Ember.View.extend
didInsertElement: ->
@$('.modal').modal('show').on 'hidden.bs.modal', =>
@get('controller').send 'close'
layout: Ember.Handlebars.compile '<div class="modal hide fade">{{yield}}</div>'
Template:
App.ModalView
.modal-header
button type="button" class="close" data-dismiss="modal" aria-hidden="true" ×
h3
| Post #
= id
.modal-body
...
回答4:
Using a component, and relying on Bootstrap's own dismissal functionality to trigger a sendAction
. willDestroyElement
takes care of tearing things down. It's in CoffeeScript and Emblem.js, because I lifted this from my code:
application.coffee:
ApplicationRoute = Ember.Route.extend
actions:
openModal: (modalName) ->
@render modalName,
into: "application"
outlet: "modal"
closeModal: ->
@disconnectOutlet
outlet: "modal"
parentView: "application"
modal-dialog.coffee:
ModalDialogComponent = Ember.Component.extend
didInsertElement: ->
@$(".modal").modal "show"
@$(".modal").on "hidden.bs.modal", => @sendAction()
willDestroyElement: ->
@$(".modal").modal "hide"
@$(".modal").off()
modal-dialog.embl:
.modal.fade
.modal-dialog
.modal-content
.modal-header
button.close type="button" data-dismiss="modal"
span aria-hidden="true" ×
span.sr-only Close
h4.modal-title Modal title
.modal-body
= yield
.modal-footer
button.btn.btn-default type="button" data-dismiss="modal" Close
button.btn.btn-primary type="button" Save
modal.embl:
= modal-dialog action="closeModal"
p Hello
回答5:
If you are looking for a more visual and simple solution to your problem, I highly recommend you check out this youtube video by Brett Valentine.
Binding to Twitter Bootstrap with Ember
I've met the developer at my local emberjs meetup, but he covers integrating bootstrap modals into projects as components.
It makes sense to integrate bootstrap elements as reusable components because you are likely going to be using them in other projects in the future.