Dans un projet Rails 2.2, les utilisateurs créent une liste de projets dans un objet de portefeuille (par exemple: PortfolioHasManyProjects
). Sur la page est un formulaire Rails pour le texte régulier, les titres, etc., ainsi que 2 listes triables; Les listes sont utilisées pour faire glisser des projets de la liste globale de projets dans votre liste de projets.RubyOnRails 2.2 + Jquery UI Sortable & AJAX: Voici comment je l'ai fait. Y a-t-il un meilleur moyen?
Il est similaire à ce qui est fait ici: http://ui.jquery.com/latest/demos/functional/#ui.sortable.
J'ai la liste de portefeuille (#drag_list) mise à jour à la modification et la soumission de ses données sérialisées via un appel AJAX. Cela se fait dans le fichier application.js:
jQuery.ajaxSetup({
'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")}
})
jQuery.fn.submitDragWithAjax = function() {
this.submit(function() {
$.post(this.action, $("#drag_list").sortable('serialize'), null, "script");
return false;
})
return this;
};
$(document).ajaxSend(function(event, request, settings) {
if (typeof(AUTH_TOKEN) == "undefined") return;
// settings.data is a serialized string like "foo=bar&baz=boink" (or null)
settings.data = settings.data || "";
settings.data += (settings.data ? "&" : "") + "authenticity_token=" + encodeURIComponent(AUTH_TOKEN);
});
/-------------------------------------------/
$(document).ready(function(){
$(".ajax_drag").submitDragWithAjax();
$("#drag_list").sortable({
placeholder: "ui-selected",
revert: true,
connectWith:["#add_list"],
update : function() {
$("#drag_list").submit();
}
});
$("#add_list").sortable({
placeholder: "ui-selected",
revert: true,
connectWith:["#drag_list"]
});
Voici où les choses se sont difficiles. Je ne savais pas comment traiter les données sérialisées et je l'ai soumis avec le formulaire au contrôleur dans le fichier new.html.erb
. Donc ce que j'ai fait était d'avoir les champs de formulaire cachés new.js.erb
dans new.html.erb
avec les données que je voudrais extraire dans le contrôleur.
est ici le new.js.erb:
$("#projects").html("");
<% r = params[:proj] %>
<% order=1 %>
<% for i in r %>
$("#projects").append("<input type=hidden name=proj[<%=order%>] value=<%=i%> />");
<% order=order+1 %>
<% end %>
qui édite new.html.erb:
<h1>New portfolio</h1>
<h2>The List</h2>
<div class="list_box">
<h3>All Available Projects</h3>
<%= render :partial => "projects/add_list" %>
</div>
<div class="list_box">
<h3>Projects currently in your new portfolio</h3>
<%= render :partial => "projects/drag_list" %>
</div>
<div style="clear:both"></div>
<br/>
<br/>
<h2>Portfolio details</h2>
<% form_for(@portfolio) do |f| %>
<%= f.error_messages %>
<h3>Portfolio Name</h3>
<p>
<%= f.text_field :name %>
</p>
<h3>URL</h3>
<p>
<%= f.text_field :url %>
</p>
<h3>Details</h3>
<p>
<%= f.text_area :details %>
</p>
<p>
<div id="projects">
<input type="hidden" name="proj" value="" />
</div>
<%= f.submit "Create" %>
</p>
<% end %>
La forme soumet ensuite la méthode créer dans le contrôleur de portefeuille :
def new
@projects = Project.find(:all)
@portfolio = Portfolio.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @portfolio }
format.js
end
end
def create
@portfolio = Portfolio.new(params[:portfolio])
proj_ids = params[:proj]
@portfolio.projects = []
@portfolio.save
proj_ids.each {|key, value| puts "Key:#{key} , Value:#{value} " }
proj_ids.each_value {|value| @portfolio.projects << Project.find_by_id(value) }
respond_to do |format|
if @portfolio.save
flash[:notice] = 'Portfolio was successfully created.'
format.html { render :action => "index" }
format.xml { render :xml => @portfolio, :status => :created, :location => @portfolio }
else
format.html { render :action => "new" }
format.xml { render :xml => @portfolio.errors, :status => :unprocessable_entity }
end
end
end
Alors enfin ma question:
Est-ce une bonne façon de le faire? Pour une raison quelconque, je pense que ce n'est pas le cas, surtout parce que tout le reste dans Rails semblait tellement plus facile et intuitif. Cela fonctionne, mais c'était l'enfer pour l'obtenir. Il doit y avoir une manière plus élégante d'envoyer des données sérialisées au contrôleur via des appels AJAX.
Comment appeler différentes actions AJAX sur la même page? Disons que j'ai eu un triable et un appel AJAX autocomplete, pourrais-je avoir un
sortable.js.erb
etautocomplete.js.erb
et les appeler à partir de n'importe quel fichier? Je ne sais pas comment configurer les contrôleurs pour répondre à cela.
Voici ma prise sur ceci: http://awesomeful.net/posts/47-sortable-lists-with-jquery-in-rails – hgmnz
Je ne comprends pas la question (et malheureusement, il y a une limite stupide rep commentant, donc je posterai ceci comme réponse). Pourquoi insérez-vous les champs cachés? Ne pouvez-vous pas simplement utiliser des ID sur les éléments <li> puis appelez 'toArray' sur le sortable plutôt que sur 'sérialiser')? Vous pouvez ajouter cette information à un seul champ de formulaire caché avant que le formulaire ne le soumette. Cela empêcherait tous les appels Ajax après la mise à jour de la liste des projets. – eelco