可重复使用的远程模式 Rails
Reusable remote modal Rails
我正在尝试创建一个可重复使用的远程模式。这个想法是创建一个模型容器并在其中渲染带有 yield
的内容,并在需要时渲染内容。
注意:所有HTML
的代码都会写在HAML
中。我正在使用 bootstrap-modal-rails gem 来处理我的模态。
我的模态容器布局(不是部分):
%div(class="modal" id="mainModal ajax-modal" tabindex="-1" role="dialog"){:'aria-labelledby'=>"mainModalLabel", :'aria-hidden'=>"true"}
%div(class="c-modal__container")
%div(class="c-modal__layout modal__content")
= yield
在我的 application.html.haml
中,我有一个 div 定义模态位置如下:
-# ...
%div(id="modal-holder")
- unless params[:nojs]
= javascript_include_tag 'desktop'
-# ...
这就是我的问题所在。我有一个 book controller
,用户可以在其中添加书籍。我有一个多步骤注册,我的 new
动作必须是我的模态。当用户点击 New book
link 时,我正在加载一个新的模式。
我的New book
link:
= link_to "New book", new_book_path, class: "c-link--navbar", data: { modal: true }
CoffeeScript(在 jQuery
中重写)用于模态(此代码来自 this article):
$(function() {
var modal_holder_selector, modal_selector;
modal_holder_selector = '#modal-holder';
modal_selector = '.modal';
$(document).on('click', 'a[data-modal]', function() {
var location;
location = $(this).attr('href');
$.get(location, function(data) {
return $(modal_holder_selector).html(data).find(modal_selector).modal();
});
return false;
});
return $(document).on('ajax:success', 'form[data-modal]',
function(event, data, status, xhr) {
var url;
url = xhr.getResponseHeader('Location');
if (url) {
window.location = url;
} else {
$('.modal-backdrop').remove();
$(modal_holder_selector).html(data).find(modal_selector).modal();
}
return false;
});
});
现在我的 new action
yield
将加载到我的远程模式中:
= form_for(@book, remote: remote, html: {role: :form}, class: "c-form") do |f|
-# Forms here...
= f.submit "Add a new book", class: "c-btn"
如果用户的信息正确,我的模式会将用户重定向到 general action
否则我想 留在同一页面上 并闪烁一条错误消息,但问题是我没有使用 partial
,它会自动将我重定向到 new action
的新页面。
我的books_controller.rb
:
class BooksController < ApplicationController
respond_to :html, :json, :js
...
def index
@books = current_user.books
end
def new
@book = current_user.books.build
respond_modal_with @book
end
def create
@book = current_user.books.build(book_params)
if @book.save
redirect_to general_book_path(@book), notice: "Saved."
else
flash.now[:notice] = "Something went wrong."
render :new
end
end
...
end
模式响应者:
class ModalResponder < ActionController::Responder
cattr_accessor :modal_layout
self.modal_layout = 'modal'
def render(*args)
options = args.extract_options!
if request.xhr?
options.merge! layout: modal_layout
end
controller.render *args, options
end
def default_render(*args)
render(*args)
end
def redirect_to(options)
if request.xhr?
head :ok, location: controller.url_for(options)
else
controller.redirect_to(options)
end
end
end
我尝试添加类似
的内容
respond_to do |format|
format.html
format.json { render json: @book }
end
到我的 create
方法,但它不起作用,仍然将我重定向到新页面。另外,我已经问过类似的 question 并且我注意到我的 JavaScript
代码在单独的页面上运行。只要我明白问题出在我的远程模态操作页面上。有人可以帮我弄清楚当用户输入错误的输入并打开我的 javascript 时如何保持在同一页面上吗?
TBH 这是一个抽象的解决方案,与您的问题没有直接关系,但它有效(bootstrap+jq,基于生产代码)
咖啡脚本
$.showModal = (title, body) ->
$("#modal").find(".modal-title").html(title)
$("#modal").find(".modal-body").html(body)
$("#modal").modal("show")
$("#modal").find(".modal-submit").click () ->
$("#modal").find("form").submit()
Html - 典型 bootstrap 模态
<div id="modal" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="<%= t :close %>" title="<%= t :close %>">
<span aria-hidden="true"></span>
</button>
</div>
<div class="modal-body">
<p></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal"><%= t :close %></button>
<button type="button" class="btn btn-success modal-submit"><%= t :save %></button>
</div>
</div>
</div>
</div>
new.js.erb 或另一个 rails 视图
$.showModal(
"<%= escape_javascript t :edit_comment %>",
"<%= escape_javascript(render 'form', :comment => @comment) %>"
);
link 打开模态
<%= link_to t(:new), [:new, comment], :remote => true, class: "btn" %>
您可能想使用自己的 ajax 请求 - 如果服务器 error/timeout
,此请求将不执行任何操作
我正在尝试创建一个可重复使用的远程模式。这个想法是创建一个模型容器并在其中渲染带有 yield
的内容,并在需要时渲染内容。
注意:所有HTML
的代码都会写在HAML
中。我正在使用 bootstrap-modal-rails gem 来处理我的模态。
我的模态容器布局(不是部分):
%div(class="modal" id="mainModal ajax-modal" tabindex="-1" role="dialog"){:'aria-labelledby'=>"mainModalLabel", :'aria-hidden'=>"true"}
%div(class="c-modal__container")
%div(class="c-modal__layout modal__content")
= yield
在我的 application.html.haml
中,我有一个 div 定义模态位置如下:
-# ...
%div(id="modal-holder")
- unless params[:nojs]
= javascript_include_tag 'desktop'
-# ...
这就是我的问题所在。我有一个 book controller
,用户可以在其中添加书籍。我有一个多步骤注册,我的 new
动作必须是我的模态。当用户点击 New book
link 时,我正在加载一个新的模式。
我的New book
link:
= link_to "New book", new_book_path, class: "c-link--navbar", data: { modal: true }
CoffeeScript(在 jQuery
中重写)用于模态(此代码来自 this article):
$(function() {
var modal_holder_selector, modal_selector;
modal_holder_selector = '#modal-holder';
modal_selector = '.modal';
$(document).on('click', 'a[data-modal]', function() {
var location;
location = $(this).attr('href');
$.get(location, function(data) {
return $(modal_holder_selector).html(data).find(modal_selector).modal();
});
return false;
});
return $(document).on('ajax:success', 'form[data-modal]',
function(event, data, status, xhr) {
var url;
url = xhr.getResponseHeader('Location');
if (url) {
window.location = url;
} else {
$('.modal-backdrop').remove();
$(modal_holder_selector).html(data).find(modal_selector).modal();
}
return false;
});
});
现在我的 new action
yield
将加载到我的远程模式中:
= form_for(@book, remote: remote, html: {role: :form}, class: "c-form") do |f|
-# Forms here...
= f.submit "Add a new book", class: "c-btn"
如果用户的信息正确,我的模式会将用户重定向到 general action
否则我想 留在同一页面上 并闪烁一条错误消息,但问题是我没有使用 partial
,它会自动将我重定向到 new action
的新页面。
我的books_controller.rb
:
class BooksController < ApplicationController
respond_to :html, :json, :js
...
def index
@books = current_user.books
end
def new
@book = current_user.books.build
respond_modal_with @book
end
def create
@book = current_user.books.build(book_params)
if @book.save
redirect_to general_book_path(@book), notice: "Saved."
else
flash.now[:notice] = "Something went wrong."
render :new
end
end
...
end
模式响应者:
class ModalResponder < ActionController::Responder
cattr_accessor :modal_layout
self.modal_layout = 'modal'
def render(*args)
options = args.extract_options!
if request.xhr?
options.merge! layout: modal_layout
end
controller.render *args, options
end
def default_render(*args)
render(*args)
end
def redirect_to(options)
if request.xhr?
head :ok, location: controller.url_for(options)
else
controller.redirect_to(options)
end
end
end
我尝试添加类似
的内容respond_to do |format|
format.html
format.json { render json: @book }
end
到我的 create
方法,但它不起作用,仍然将我重定向到新页面。另外,我已经问过类似的 question 并且我注意到我的 JavaScript
代码在单独的页面上运行。只要我明白问题出在我的远程模态操作页面上。有人可以帮我弄清楚当用户输入错误的输入并打开我的 javascript 时如何保持在同一页面上吗?
TBH 这是一个抽象的解决方案,与您的问题没有直接关系,但它有效(bootstrap+jq,基于生产代码)
咖啡脚本
$.showModal = (title, body) ->
$("#modal").find(".modal-title").html(title)
$("#modal").find(".modal-body").html(body)
$("#modal").modal("show")
$("#modal").find(".modal-submit").click () ->
$("#modal").find("form").submit()
Html - 典型 bootstrap 模态
<div id="modal" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="<%= t :close %>" title="<%= t :close %>">
<span aria-hidden="true"></span>
</button>
</div>
<div class="modal-body">
<p></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal"><%= t :close %></button>
<button type="button" class="btn btn-success modal-submit"><%= t :save %></button>
</div>
</div>
</div>
</div>
new.js.erb 或另一个 rails 视图
$.showModal(
"<%= escape_javascript t :edit_comment %>",
"<%= escape_javascript(render 'form', :comment => @comment) %>"
);
link 打开模态
<%= link_to t(:new), [:new, comment], :remote => true, class: "btn" %>
您可能想使用自己的 ajax 请求 - 如果服务器 error/timeout
,此请求将不执行任何操作