2017-10-13 13 views
9

Je suis en train de mettre en œuvre des modèles imbriqués, voici l'entrée du fichier d'itinéraire:Comment implémenter remote: fonctionnalité vraie sans link_to?

resources :projects do 
    resources :instances 
end 

Ce qui suit est l'extrait de code pour le contrôleur de projet:

# GET /projects/new 
def new 
    @project = Project.new 
    @project.instances.build 
end 

et la vue sous forme de projet:

<%= simple_form_for(@project) do |f| %> 
    ... 
    <%= label_tag :instance_count, "Instance Count" %> 
    <%= select_tag :instance_count, options_for_select([0, 1, 2, 3, 4, 5], 0) %> 
    ... 
<% end %> 

Maintenant, quand je change le nombre de nombre d'instances, j'ai besoin d'afficher les champs d'instance plusieurs fois ci-dessous le formulaire ci-dessus. Voici le code partiel pour que:

<%= form.simple_fields_for :instances do |i| %> 
    ... 
<% end %> 

Fondamentalement, je besoin d'appeler <%= render 'instances/form', form: f %> du fichier javascript de projet. Cela devrait fonctionner comme un lien avec l'option remote: true. Mais dans ce cas, il n'y a pas de lien, mais sur l'événement de changement, le formulaire doit être affiché. Comment devrais-je l'implémenter?

+0

lorsque vous cliquez sur '@project [: instance_count]' et changer le numéro, vous souhaitez afficher un nombre différent de champs d'entrée 'instances'? Est-ce que cela nécessite AJAX? peut-être qu'il suffit juste d'écouter cet événement click sur ce div pour ajouter un nouveau div sur cette page et quand vous soumettez le formulaire, assurez-vous que le submit fonctionne pour ces champs .... Je pense à poster une réponse .. champs d'entrée c'est un peu compliqué parce que le formulaire a un 'token' qui évite CSRF, aussi le submit doit être effectué peut-être avec' Javascript' et vous devrez créer une requête jquery '.post()' –

+0

Votre déclencheur entendre est le clic sur le '<% = select_tag: instance_count, options_for_select ([0, 1, 2, 3, 4, 5], 0)%>' so '$ (' # select_tab '). div à la page en fonction du div.value() résultat); ', il n'y a pas d'interaction avec le serveur. Ensuite, vous devez faire la demande 'post' dans le fichier javascript avec cette fonction https://api.jquery.com/jQuery.post/ –

Répondre

0

Vous devez appeler une fois le code côté serveur car instances/form contient du code qui ne peut être rendu que sur le serveur.
Vous devez d'abord faire un appel ajax (par exemple, instance_new_path), puis vous devez rendre le formulaire sur cette vue (instance_new.js.erb).

exemple .js.erb

$("#new_form").html("<%= escape_javascript(render partial: 'instances/form') %>"); 
+0

Passer l'objet de formulaire est le peu difficile ici (je trouve) - Comment serait vous rendez cela disponible au partiel? – SRack

+0

Cela doit être fait sur le contrôleur, également spécialisé peut être fait après la fourniture du code complet. –

0

standard est de faire une partie appelée app/views/instances/_instance_fields.html.erb. Ensuite, vous pouvez simplement le charger dans votre formulaire et le rendre caché.

<%= simple_form_for(@project) do |f| %> 
    <%= render 'instances/_instance_fields %> 
<% end %> 

Couverture _instance_fields partielle avec une sorte de récipient, comme <fieldset class='instance_fields' style='display:none'>. En outre, vous ne devriez pas utiliser l'objet formulaire ici, allez simplement avec les entrées text_field_tag ​​/ checkbox_tag. Ensuite, lorsque vous avez besoin d'ajouter d'autres instances, copiez ces extraits cachés autant de fois que nécessaire et configurez les noms propres pour les entrées (pour être compatible avec accepts_nested_attributes_for). Ping me pour fournir plus de détails et d'assistance.

C'est une approche qui a été utilisée dans le vrai projet. L'appel ajax de feu chaque fois que vous devez ajouter plus d'instances n'est pas optimisé du tout.

+0

J'utilise déjà '<% = render 'instances/form', forme: f%>' .. –

+0

Vous devez stocker cette pièce dans un modèle caché et copier ce modèle pour chaque nouvelle instance. Après la copie, vous devez configurer les noms propres à l'aide de javascript. Juste quelques notes spécifiques ce qui ne fonctionne pas dans l'approche que je vous ai donnée. Vous ne devriez pas utiliser l'attribut 'from'. C'est absolument inutile dans un cas de template, car il faudra encore gérer les attributs d'entrée 'name' manuellement en javascript – AntonTkachov

0

Je vous suggère d'utiliser https://github.com/nathanvda/cocoon

Ou vous pouvez utiliser aproche similaire: rendre partielle sous forme initiale (avec display: none), puis retirer et enregistrer les champs partiels avec js et les cloner pour former lorsque le sélecteur est frappé .

0

Créer un fichier .js et la charge à l'intérieur projects/new.html.erb, qui exécutera chaque fois qu'il ya un changement de select valeur et crée une demande post-instances/new contrôleur qui rend instances/new.js.erb chaque fois qu'il est touché.

# GET /instances/new 
def new 
    @f = Instance.new 
end 

instances/new.js.erb

$('#instance-form-wrapper').append(<% escape_javascript(render 'instances/form', form: @f) %> 

charge.js

$(document).on('change', 'select#some-id-name', function(){ 
    var v = $(this).val(); 
    $('#instance-form-wrapper').html('') ; 
    while(v--) $.post('/instances/'); 
}) 

Bien que vous ne devriez pas utiliser comme ça. Plutôt charger un instance champ déjà dans votre code, gardez-le caché, comme vous avez déjà instance disponible dans votre project. En outre, vous n'avez pas besoin de nouvelles données chaque fois que vous le restituez. Simplement lors de la sélection de la valeur 1, vous pouvez show votre champ instance et si la valeur est > 1 vous pouvez utiliser clone pour le copier davantage.