How to reset/clear form within my create.js.erb? - javascript

I can't get my form to reset correctly. It submits and it goes to the database but everything remains on the form.
Here is my code:
DogsController
def create
#dog = current_user.dogs.new(params[:dog])
if #dog.save
format.js
else
format.js
end
end
dog/create.js.erb
$('.add-dog-form').html('<%= escape_javascript(render(:partial => 'dogs/form', locals: { dog: #dog })) %>');
$('.add-dog-form > form')[0].reset(); // doesn't work
dog/new.js.erb
$('.add-dog-form').html('<%= escape_javascript(render(:partial => 'dogs/form', locals: { dog: #dog })) %>');
dogs/_form
<%= form_for(#dog, :remote => true) do |f| %>
<%= f.label :name, "Name" %>
<%= f.text_field :name %>
<%= f.submit "Add Dog" %>
<% end %>
I create dogs at the Pets view instead of the dogs.
PetsController
def add
#dog = Dog.new
#cat = Cat.new
#bird = Bird.new
end
pets/add.html.erb
I click on the tab which changes it to the Dog Tab using Twitter Bootstraps Tabbable Nav ability
<div class="tabbable">
<ul class="nav nav-tabs">
<li class="active">
Cat
</li>
<li>
Dog
</li>
<li>
Bird
</li>
</ul>
<div class="tab-content">
<div class="tab-pane active add-cat-form" id="tab1">
<%= render "cats/form" %>
</div>
<div class="tab-pane add-dog-form" id="tab2">
<%= render "dogs/form" %>
</div>
<div class="tab-pane add-bird-form" id="tab3">
<%= render "birds/form" %>
</div>
</div>
</div>
How can I reset the form if it gets created?

Try giving the form an id:
<%= form_for(#dog, :remote => true, :html => { :id => 'dog_form' } ) do |f| %>
and $('#dog_form')[0].reset();.
Alternatively, you can do $(":input:not(input[type=submit])").val("");.

Well it seems my error was in my files themselves. I had created the js files as partials instead of regular pages. i.e. _create.js.erb should be create.js.erb. I also had to add respond_to do |format| in the controller create action. Now I got everything working correctly.

Related

Rails 6 Ajax page keeps refreshing when creating category

I'm new to RoR and i have this problem in Rails 6 where i am trying to add a category to a categories list with ajax so that when i submit my form, the page shouldn't refresh. But it keeps refreshing.
I followed this tutorial and split the list of into a _category.html.erb partial and created a create.js.erb file that appends to the list but i don't get the same results.
here is my index.html.erb:
<body>
<main>
<section class="hero is-link is-fullheight pt-3">
<div class="hero-body">
<div class="container is-align-self-flex-start">
<h1 class="title has-text-centered">categories</h1>
<!-- container for the list of categories -->
<div class="container" id='category'>
<%= render #category %>
</div>
<h2 class="is-size-4">add a category</h2>
<%= render 'form', category: #category %>
</div>
</div>
</section>
</main>
</body>
this is my category list partial:
<!-- Loop over categories and add delete btn-->
<% #categories.each do |category| %>
<div class="columns is-mobile card mb-4">
<div class="column is-align-self-center ">
<p class="is-size-5"><%= category.name %></p>
</div>
<div class="column is-narrow">
<button class="button is-danger"><%= link_to 'delete', category, method: :delete, data: { confirm: 'Er du sikker?' } %></button>
</div>
</div>
<% end %> <!-- end of loop -->
this is my form partial for the input and submit btn:
<%= form_with(model: category) do |form| %>
<% if category.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(category.errors.count, "error") %> prohibited this category from being saved:</h2>
<ul>
<% category.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field has-addons">
<%= form.text_field :name , ({:class => "input", })%>
<%= form.submit "add", ({:class => "button is-primary", })%>
</div>
<% end %>
this is my create method in my categories controller that i suspect is the culprit because when i remove the format.html and format.json i get
"ActionController::UnknownFormat in CategoriesController#create"
def create
#categories = Category.all
#category = Category.new(category_params)
respond_to do |format|
if #category.save
format.js
format.html { redirect_to action: "index", notice: "Category was successfully created." }
format.json { render :show, status: :created, location: #category }
else
format.html { render :"index", status: :unprocessable_entity }
format.json { render json: #category.errors, status: :unprocessable_entity }
end
end
end
this is the js file to append the new category to the list:
var body = document.getElementByID("category");
body.innerHTML = "<%= j render #categories %>" + body.innerHTML;
I have tried
This tutorial with jquery also but that also reloads on submit.
I have triple checked that i don't have "local:true" anywhere.
Changed tried #category instead of #categories in some places with no luck
I generated the project with a scaffold
Is there something that i'm missing?
Any guidance is greatly appreciated.
You are not using data-remote attribute for your form. This attribute means the form will submit the results via Ajax.

Dynamically generate copies partial form based on user selection in a nested form

I'm trying to create a form that will generate copies of a nested form depending on a user's selection. I have 3 models: Visualizations, which has_many Rows, which has_many Panes.
I want to be able to allow the user to click a small dropdown menu that will generate a row and then select 1, 2, or 3 panes. Depending on their selection, this will generate the form of their choice from a render.
here is an example where a user chose 3 panes (3 upload boxes for images) with just styled divs in place of the form
For starters. I know I would need to change up my controller a bit, but I'm not sure how to do that with a nested form since in every example I've seen so far, you need to predetermine how many times you would "build" a nested model form (not sure if that is the correct terminology). I'm not sure how to make that part dynamic.
Here is what I mean:
//visualization_controller.rb
def new
#visualization = Visualization.new
rows = #visualization.rows.build
panes = rows.panes.build
end
here is an example of the render that would be called if the usr wanted to generate a row with just 1 Pane:
<div class="medium-12 columns one_box_wrapper first" style="display:none">
<%= f.fields_for :rows, Row.new do |r| %>
<%= r.label :rowtitle %>
<%= r.text_field :rowtitle %>
<div class="nested" style="display:inline-block">
<%= r.fields_for :panes, Pane.new do |p| %>
<%= p.label :text %>
<%= p.text_field :text %>
<div class="mehv">
<img id="img_prev" width=300 height=300 src="#" alt="your image" class="img-thumbnail hidden"/> <br/>
<span class="meh">
Upload Pane Image<%= p.file_field :pane_photo, id: "pane_photo" %>
</span>
<%= p.hidden_field :pane_photo_cache %>
</div>
<% end %>
</ul>
</div>
<% end %>
</div>
Is this possible in rails? I feel like javascript would come into play but I don't think you are allowed to render server-side code through JS.
I feel a bit in over my head with this and any help would be greatly appreciated!
EDIT
I ended up using cocoon gem as it seems to have made my life a lot easier however.. I can't get the visualizations to all display on the index page! I'm not sure what the issue is.. The cover Title and Image show up but nothing else does!
//schema.rb
create_table "panes", force: :cascade do |t|
t.integer "row_id", null: false
t.text "text"
t.string "pane_photo"
end
create_table "rows", force: :cascade do |t|
t.integer "visualization_id", null: false
t.string "rowtitle"
end
create_table "visualizations", force: :cascade do |t|
t.string "title", null: false
t.string "cover_image"
end
//controller.rb
class VisualizationsController < ApplicationController
before_action :authenticate_user!, except: [:index, :show]
before_action :authorize_user, except: [:index, :show]
helper_method :resource
def index
#visualizations = Visualization.all
#visualization = Visualization.new
end
def new
#visualization = Visualization.new
rows = #visualization.rows.build
panes = rows.panes.build
end
def create
#visualization = Visualization.new(visualization_params)
if #visualization.save
redirect_to edit_visualization_path(#visualization)
else
render :new
end
end
def edit
#visualizations = Visualization.all
#visualization = Visualization.find(params[:id])
end
protected
def visualization_params
params.require(:visualization).permit(:title, :cover_image, rows_attributes: [:visualization_id, :rowtitle, panes_attributes:[:text, :pane_photo]])
end
//index.html
<div class="visual_wrap text-center">
<ul class="no-bullet text-center">
<% #visualizations.each do |visualization| %>
<li class="text-center">
<div class="row visualization text-center">
<%= image_tag visualization.cover_image.to_s, id: "visualization_image", class: "output_image" %>
<p class="visualization_title"><%= visualization.title %></p>
<p>+</p>
</div>
<div class="placeholder">
<% visualization.rows.each do |row| %>
<%= row.rowtitle %>
<% row.panes.each do |p| %>
<%= p.text %>
<%= image_tag p.pane_photo.to_s, id: "pane_image", class: "output_image" %>
<% end %>
<% end %>
</div>
</li>
<% end %>
</ul>
</div>
//new.html.erb
<% if user_signed_in? %>
<% if current_user.admin? %>
<div class="try">
<div class="breadcrumb-wrapper">
<ul class="breadcrumbs">
<%= form_for #visualization, :html => {:multipart => true} do |f| %>
<li>Preview</li>
<li><div class="separating-bar">|</div>
<li><input type="submit" name="commit" value="Save" class="save button secondary"></li>
</ul>
</div>
<div class="cover_image text-center">
<div class="row pre_img_prev">
<div class="gray_bar"></div>
<div class="img_prev">
<img id="img_preview" src="#" alt="your image" class="img-thumbnail hidden text-center"/>
<input type="text" name="visualization[title]" id="visualization[title]" class="inputtext" />
<label for="visualization[title]" id="text_preview">+ Add Title</label>
<div class="trash-can_title">
<i class="fa fa-trash fa-3x" aria-hidden="true"></i>
</div>
</div>
<input type="file" name="visualization[cover_image]" id="visualization_cover_image" class="inputfile" />
<label for="visualization_cover_image">+ Add Cover Image</label>
<%= f.hidden_field :cover_image_cache %>
<div class="trash-can_cover">
<i class="fa fa-trash fa-3x" aria-hidden="true"></i>
</div>
</div>
</div>
<div class="row linkstest">
<div class="rows">
<%= f.fields_for :rows, Row.new do |task| %>
<%= render 'row_fields', f: task %>
<% end %>
<div class="links">
<%= link_to_add_association "Add Row", f, :rows %>
</div>
</div>
<% end %>
<% end %>
<% end %>
</div>
</div>
You don't need really need JS except to make it more "snappy". I think what you are looking for are Nested Forms.
Take a look at RaisCast it's a bit outdated but it's a good foundation.
You might want to look into Cocoon gem to help you create the new fields dynamically.
Rails nested_form inside nested_form
Update
If you don't want to use Javascript at all, you need to make an extra request to the controller to tell it to initialize (build) the rows and panes for you so that it renders the empty fields in the view.
For example:
def new
#visualization = Visualization.new
num_rows = params[:num_rows]
num_rows.each { #visualization.rows.build }
end
You would also need to have the number of panes in each row, so the parameter would have to be inside the row attributes, e.g. params[:visualization][:rows][0][:num_panes], and using that parameter you initialize the panes in the row. It's probably best to put that logic in a Factory service.
However if you create the empty fields using JS you can save yourself from making that extra request and all that logic. This is because Rails will automatically initialize (build) the rows and panes if you give it the right attributes, such as:
{
visualization: {
rows_attributes: {
# These are the attributes from an existing record
0: {
id: 39,
panes_attributes: {
0: {
id: 992
}
}
},
# This is a new set of attributes for a new record
# passed by the fields generated by cocoon where xxx
# and yyy are random numbers
xxxx: {
panes_attributes: {
yyyy: {
}
}
}
}
}
}
Then all you need to do in your controller is:
def new
# visualization_params are the permitted attributes
#visualization = Visualization.new(visualization_params)
end

Rails: Checkbox to change the value of a variable on click

I have a basic to do type app and I am trying to change the variable completed for an item to the current date/time when I click a checkbox. I found this post, which has led me to the following code structure:
My lists#show, on which items are created, checked off (updated), edited, and deleted:
<div class="container">
<div class="row" style="height: 70px"></div>
</div>
<div class="col-xs-10 col-xs-push-1 container">
<div class="md-well">
<h1 class="text-center"><%= #list.name %></h1>
<% if #items.count == 0 %>
<h4 class="text-center">You don't have any items on this list yet! Want to add some?<h4>
<% elsif #items.count == 1 %>
<h4 class="text-center">Only <%= #items.count %> Item To Go!</h4>
<% else %>
<h4 class="text-center">You Have <%= #items.count %> Items To Go!</h4>
<% end %>
<%= render 'items/form' %>
<% #items.each do |item|%>
<p>
<%= form_for [#list, item], class: "inline-block", id: 'item<%= item.id %>' do |f| %>
<%= f.check_box :completed, :onclick => "$this.parent.submit()" %>
<% end %>
<%= item.name %>
( <%= link_to "Delete", list_item_path(#list, item), method: :delete %> )
</p>
<% end %>
<div class="text-center">
<%= link_to "Back to My Lists", lists_path %>
</div> <!-- text-center -->
</div> <!-- well -->
</div> <!-- container -->
Here is my update method in my items_controller (which I believe has jurisdiction instead of the lists_controller even though it is the lists#show page because it is an item being updated:
def update
#list = List.friendly.find(params[:list_id])
#item = #list.items.find(params[:id])
#item.name = params[:item][:name]
#item.delegated_to = params[:item][:delegated_to]
#item.days_til_expire = params[:item][:days_til_expire]
#item.completed = params[:item][:completed]
#item.user = current_user
if #item.update_attributes(params[:item])
#item.completed = Time.now
end
if #item.save
flash[:notice] = "List was updated successfully."
redirect_to #list
else
flash.now[:alert] = "Error saving list. Please try again."
render :edit
end
end
Here is what is currently appearing:
And here are the two problems I'm having:
LESS IMPORTANT PROBLEM: The checkboxes should be displayed inline with the list items but aren't. My class inline-block simply makes links to this in the application.scss file:
.inline-block {
display: inline-block !important;
}
MORE IMPORTANT PROBLEM: Even after the checkbox is clicked, the value for completed remains nil as per my console:
[6] pry(main)> Item.where(name: "Feed Dexter")
Item Load (0.1ms) SELECT "items".* FROM "items" WHERE "items"."name" = ? [["name", "Feed Dexter"]]
=> [#]
Any ideas how to make this functional?

Only show taxonomies that belong to the selected store model Ruby

When a store is selected I would only like to see the taxonomies that belong to the selected store. Does anyone have any idea how I might do this? Either with Ruby or Javascript
<h3>Stores Offered In</h3>
<ul class="multi-column-checkbox">
<% for store in Store.all %>
<li><%= check_box_tag "idea[store_ids][]", store.id,
#idea.stores.include?(store) %> <%= store.name %></li>
<% end %>
</ul>
<br />
<h3>Taxonomies Offered In</h3>
<% for store in Store.all %>
<% if store.has_taxonomies? %>
<ul class="multi-column-checkbox">
<h4><%= store.name %></h4>
<% for taxonomy in store.taxonomies %>
<li><%= check_box_tag "idea[taxonomy_ids][]",
taxonomy.id, #idea.taxonomies.include?(taxonomy) %> <%= taxonomy.name %></li>
<% end %>
</ul>
<% end %>
<% end %>
Ok -- lots going on here. First of all, I'm making the assumption that you're using rails 3 or rails 4
Also it looks like this is nested into the ideas model, which not taken into account here, you'll have to modify the code for that.
Firstly - Try not to make calls directly to a model in a view unless you absolutely have to, that should be done in your controller. Also, in your view make sure you have a binding element for taxonomies for the jquery call you'll make later.
your_main_view_referenced_in_your_question.html.erb
<h3>Stores Offered In</h3>
<ul class="multi-column-checkbox">
<%- #stores.each do |store| %>
<li>
<%= check_box_tag "store[ids]", store.id, false, :data => {:remote => true, :url => url_for( :action => 'get_taxonomies', :id => store.id ), :method => :put}, :class => 'input-large' %>
<%= store.name %>
</li>
<% end %>
</ul>
<br/>
<div id="taxonomies">
</div>
Next you need to create a controller action to respond to your ajax call.
stores_controller.rb
### Add an action to let you do an ajax call
def get_taxonomies
#store = Store.find params[:id]
end
Now you need to create a ujs file that is rendered from your controller action In my example I named the controller action get_taxonomies so by default the view rendered will be get_taxonimies.js.erb
get_taxonomies.js.erb
if ($(".store_" + <%= params[:id] %>).length) {
$(".store_" + <%= params[:id ] %>).remove();
} else {
$('#taxonomies').append("<%= escape_javascript(render(partial: '/stores/taxonomy', locals: {stores: #stores } )) %>");
}
if ($("[class^=store_]").length > 0) {
if ( $('#taxonomies').find('h3').length ) {
// do nothing - leave the h3 where it is
} else {
$('#taxonomies').prepend("<h3>Store Taxonomies</h3>");
}
} else {
$('#taxonomies').find("h3").remove();
}
Now while you could write all your html inline in the js file, it's kind of ugly and easier to edit it later if you put it in a partial - since the js.erb file is calling taxonomy, you'll need a partial with the same name
_taxonomy.html.erb
<div class="store_<%=#store.id%>">
<h4><%= #store.name %></h4>
<ul class="multi-column-checkbox">
<%- #store.taxonomies.each do |taxonomy| %>
<li>
<%= check_box_tag "[taxonomy_ids][]", taxonomy.id, false %>
<%= taxonomy.name %>
<% end %>
</li>
</ul>
</div>

How can I reset certain fields when my form is submitted?

I have my store form that's created by ajax and want to reset certain fields that it has. Here is my code, starting from where the form is rendered all the way to its own views:
Where its rendered:
pets/index.html.erb
<div class="tabbable">
<ul class="nav nav-tabs">
<li class="active">
Store
</li>
</ul>
<div class="tab-content">
<div class="tab-pane active add-store-form" id="tab1">
<%= render "stores/form" %>
</div>
</div>
</div>
How it's created:
Note: Both my new and create view have the same exact code.
new.js.erb & create.js.erb (just this 1 line)
$('.add-store-form').html('<%= escape_javascript(render(:partial => 'stores/form', locals: { store: #store })) %>');
Now on my Store form I want to reset the fields with a # by them:
<%= form_for(#store, :remote => true, :html => { :class => "add-form", :id => "sform" }) do |f| %>
# <%= f.text_field :name %>
# <%= f.check_box :personal %>
<%= f.collection_select :category_id, Category.all, :id, :name, {}, {} %>
# <%= f.text_field :address %>
<%= f.text_field :website %>
# <%= f.text_field :phone_number %>
<%= f.submit "Create" %>
How do I reset these certain fields only?
This is kind of a duplicate question of Clear form fields with jQuery .
So, you should include a js file (not new.js.erb or create.js.erb) that has a function like this:
$('#sform').live('submit', function() {
$('#name').val(""); # this only resets the name field, provided it has the id 'name'
});
You have other examples in the answers to that question I linked to. Just notice that they use the click on a button to reset the fields while I suggested using your form submit event when you click your Create button.

Categories

Resources