Cleaning up a form from a remote modal - javascript

I am triggering a remote modal like this:
<li><a data-toggle="modal" href="/login" data-target="#modal">Sign in</a></li>
I build the 'route' variable on Javascript, and then load the Modal:
$('#modal').modal({
show: true,
remote: route
});
... where route is a variable that depending on its value, tells me where to fetch the data from.
These pages I am loading for the most part contain forms for sign in, user registration, etc... They load successfully.
The problem arises when I try to close this window and open it up again. The form is not cleared. This means, if I tried to login and the login failed and error messages were shown, they will appear when I click on the sign in button again.
For this example, the login HTML that is loaded contains the following:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<%= csrf_meta_tags %>
<title>Sign in to Chocolatechix</title>
</head>
<body>
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
</div>
<%= form_for #user_session, url: user_session_path, method: :post, html: { class: 'form-horizontal', role: 'form' } do |f| %>
<div class="modal-body">
<div class="row lower-space">
<div class="col-xs-10 col-xs-offset-1">
<%= f.text_field :email, class: 'form-control email_field', placeholder: 'E-mail Address' %>
</div>
</div>
<div class="row lower-space">
<div class="col-xs-10 col-xs-offset-1">
<%= f.password_field :password, class: 'form-control password_field', placeholder: 'Password' %>
</div>
</div>
<div class="row">
<div class="col-xs-10 col-xs-offset-1">
<%= f.submit 'Sign In', class: 'btn btn-primary full-width' %>
</div>
</div>
<div class="row lowest-space">
<div class="col-xs-10 col-xs-offset-1">
Forgot password?
</div>
</div>
<div class='row'>
<div class="col-xs-4 col-xs-offset-1 center new-text bold">
New user?
</div>
<div class="col-xs-4 col-xs-offset-1 center">
<a class="btn btn-success" href="/become">Create account</a>
</div>
</div>
<div class="row">
<div class="col-xs-12" id="error_messages">
</div>
</div>
</div>
<div class="modal-footer">
</div> <!-- /modal-footer -->
<% end %>
<script type="text/javascript">
$( document ).ready(function(){
// process the form
$('form').submit(function(event) {
// get the form data
// there are many ways to get this data using jQuery (you can use the class or id also)
var formData = {
'user_session[email]' : $('.email_field').val(),
'user_session[password]' : $('.password_field').val(),
'authenticity_token': $('input[name=authenticity_token]').val(),
'utf8': $('input[name=utf8]').val()
};
// process the form
$.ajax({
type : 'POST', // define the type of HTTP verb we want to use (POST for our form)
url : '/user_session', // the url where we want to POST
data : formData, // our data object
dataType : 'json', // what type of data do we expect back from the server
encode : true
}).done(function(data) {
console.log(data);
if(!data.logged_in){
$('#error_messages').html('<span class="label label-danger">' + data.error+ '</span>');
}
else {
window.location.replace("/");
}
});
// stop the form from submitting the normal way and refreshing the page
event.preventDefault();
});
});
</script>
</body>
</html>
So in this case, the error messages keep showing.
Any ideas?
Edit: So I'm thinking that trying to invoke a hide event and try to clean it up from there might work. (See Bind a function to Twitter Bootstrap Modal Close)
I am trying to call this event this way:
$('#modal').modal({
show: true
});
$('#modal').on('hidden.bs.modal', function () {
alert('Foo');
});
... but this is not triggered.
Ideas?
Edit 2: Yet another attempt:
$(document).on('hide.bs.modal','#modal', function () {
alert('Foo');
}).modal({
show: true,
remote: route;
});
The alert does not fire.

you can do like this
<li><a data-toggle="modal" href="/login" onclick="test()">Sign in</a></li>
function test(){
$("#formid")[0].reset();
$('#modal').modal({
show: true
});
}

Related

How do I autofocus to text input field in modal? Rails 7, Bootstrap 5

I have a search button in the top navbar. When the user clicks, a modal opens with a text input field. I want the keyboard focus to be automatically inside the text input field when the modal opens.
Here is the search modal code:
<div class="modal" id="searchModal" tabindex="1" aria-labelledby="searchModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="searchModalLabel">Search parks</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<%= search_form_for #q, url: :parks do |f| %>
<%= f.hidden_field :has_entrance_fee_eq %>
<%= f.hidden_field :region_eq %>
<div class="form-group">
<%= f.text_field :name_en_or_name_he_or_description_en_or_description_he_cont,
autofocus: true,
placeholder: "Search for a park (English or Hebrew)",
class: "form-control" %>
</div>
<div class="form-group">
<%= f.submit 'Search parks', name: "", class: "btn btn-primary" %>
</div>
<% end %>
</div>
</div>
</div>
</div>
I've already tried simply adding autofocus: true in the rails form, but it doesn't work:
<div class="form-group">
<%= f.text_field :name_en_or_name_he_or_description_en_or_description_he_cont,
autofocus: true,
placeholder: "Search for a park (English or Hebrew)",
class: "form-control" %>
</div>
The Bootstrap documentation says:
Due to how HTML5 defines its semantics, the autofocus HTML attribute has no effect in Bootstrap modals. To achieve the same effect, use some custom JavaScript:
var myModal = document.getElementById('myModal')
var myInput = document.getElementById('myInput')
myModal.addEventListener('shown.bs.modal', function () {
myInput.focus()
})
But I'm not really familiar with Javascript so not sure where/how to use this code, if this is indeed the right direction... In general I'm new to coding so any help would be much appreciated, the more specific the better!
Update:
I tried adding the following code to the search modal but it didn't work:
<script>
// Get the modal and the input element
var myModal = document.getElementById('searchModal')
var myInput = document.querySelector('input')
// Add a listener for the shown.bs.modal event on the modal
myModal.addEventListener('shown.bs.modal', function() {
// When the modal is shown, focus the input element
myInput.focus()
})
</script>

Manually adding select options does not work correctly every time, and even if it did, the second atempt is always a failure

I want to create a modal with three text_fields, and when submitting, I need to preventDefault on the browser (to not reload the page, in case any data was put beside modal), then send data to the backend through AJAX, and then manually update the select_2 with submitted option.
Changing variables types, splitting .trigger("change") into a new line, or zeroing option object after appending it, doesn't seem to change anything.
<div class="sampling-register">
<div class="ibox">
<div class="ibox-content">
<form>
<div class="section">
<div>
<%= select_tag :client, grouped_options_for_select(#clients),
:include_blank => 'Wybierz klienta', class: 'select2_demo_2', required: true %>
<button type="button" data-toggle="modal" data-target="#client_modal">
<%= image_tag 'laboratory/add_circle_blue' %>
</button>
</div>
</div>
</form>
</div>
</div>
<div class="modal inmodal" id="client_modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content animated fadeIn">
<div class="modal-header">Dodaj klienta</div>
<%= form_for :client, url: clients_path, :html => {:id => "form_add_client"} do |f| %>
<div class="modal-body">
<%= f.hidden_field :laboratory_id, value: current_user.company.laboratory.id %>
<%= f.text_field :name, class: 'form-control', placeholder: 'Nazwa', required: true %>
<%= f.text_field :address, class: 'form-control', placeholder: 'Adres' %>
</div>
<div class="modal-footer">
<button class="discard" data-dismiss="modal">Anuluj</button>
<button class="submit">Dodaj</button>
</div>
<% end %>
</div>
</div>
</div>
<script>
let form = $("#form_add_client");
let submitBtn = form.find(".submit");
let client_select_tag = $("#client");
form.on("submit", function (event) {
event.preventDefault();
let name = $('#client_name').val();
let client_address = $('#client_address').val();
let laboratory_id = $('#client_laboratory_id').val();
$.ajax({
url: '/clients',
method: 'POST',
dataType: "json",
data: {
client: {
name: name,
address: client_address,
laboratory_id: laboratory_id
},
}
})
.done(function (result) {
if (result.error) {
toastr["error"](result.error);
} else {
let option = new Option(result.data.name, "{lab_client_id: " + result.data.id + "}", false, true);
client_select_tag.children().eq(2).append(option).trigger('change');
$('#client_modal').modal('hide');
toastr["success"]("Klient dodany poprawnie");
}
})
})
</script>
The problem is, it does works, but then sometimes doesn't (like every third try), and even if it works once, then every other attempt is a failure until I reload the page. After reloading, it seems like a coin throw again.
It does trigger the appended option as selected EVERY time, but actually appending to the select list does not occur so often.
OK, seems that changing
client_select_tag.children().eq(2).append(option).trigger('change');
into
client_select_tag.select2().children().eq(2).append(option).trigger('change');
makes the code works

uncaught TypeError: ajaxForm is not a function in rails version 5?

I am trying to submit the modal form using ajaxForm and display the response in modal itself. But, I am getting uncaught type error (...).ajaxForm is not a function.
Basically I want to create a modal form for lesson creation form and have to submit , my app consists of both API controller and front end controller.
api!
param_group :lesson
description 'creates a lesson'
example "
{
'id': 12,
'title': 'MUDRAS',
'active_video_id': 3,
'description': 'Description of the lesson',
'points': null,
'is_public': '1',
'videos': [
{
'video': {
'id': 1,
'video': {
'url': '/uploads/video/video/1/250-authentication-from-scratch.mp4'
},
'title': null,
'storage_type': 'Lesson',
'storage_id': 12
}
},
]
}"
def create
#lesson = Lesson.new(lesson_params)
#lesson.creator = current_user
if #lesson.save
render json: {
success: true,
message: "Lesson created Successfully"
}
else
render json: { success: false, message: "Could not Create : #{#lesson.errors.full_messages.join(', ')}" }
end
end
def new
#lesson = Lesson.new
end
The above code is my API controller.The below codes are my Front end controller and lesson related forms.
def create
#lesson = Lesson.new(lesson_params)
if #lesson.save
render json: {
success: true,
message: "Lesson Created Successfully"
}
else
render json: {
success: false,
message: "Lesson Creation Failed"
}
end
end
I need to display the "New Lesson" button in Lesson Index page.
lessons/index.html.erb
<% unless current_user.student? %>
<div class="container-fluid">
<div class="col-md-3 col-sm-3 text-left">
<div id="newLesson" class="lesson-category btn-danger" lesson_url="<%= new_lesson_path %>">
<i class="fa fa-plus"></i> ADD LESSON
</div>
</div>
</div>
<div class="hidden" id="newLessonForm">
<% #lesson = Lesson.new ; #lesson.videos = [Video.new] %>
<%= render "lessons/form" %>
</div>
<% end %>
<%= render "shared/primary_modal" %>
<div class="container-fluid">
<div class="col-md-3 col-sm-3 text-left">
<h2 class="main-tab tab-active">LESSONS</h2>
</div>
<div class="col-md-9">
<div class="col-md-12 text-right">
<h2 class="main-tab tab-inactive"><a id="responsesLink" class="blacko" href="#"><%= "MY" if current_user.student? %> RESPONSES</a></h2>
</div>
</div>
<div class="col-md-12"><hr/></div>
<!-- Lessons of this course Go here -->
<div class="col-md-3">
<% #lessons.each do |lesson| %>
<div id="lesson_<%= lesson.id %>" class="pill video-view lesson-load" data-lesson-id="<%= lesson.id %>" data-src="<%= lesson.active_video_url %>"><%= lesson.title %></div>
<% end %>
<!-- <div class="pill pill-inactive">Something</div> -->
</div>
<!-- Lesson Content goes here -->
<div class="col-md-9">
<div class="row">
<div class="col-md-12">
<%= render "shared/video_player" %>
</div>
</div>
<div id="lessonContent">
</div>
</div>
</div>
<script>
$("#newLesson").click(function(){
var lesson_path = $(this).attr("lesson_url");
$.get(
lesson_path,
function(content){
$("#primaryModalContent").html(content);
$("#format").val('js');
$("#primaryModal").modal("show");
}
);
});
</script>
My lesson creation form is given as a partial.
<div class="col-md-12">
<%= simple_form_for #lesson, html: {class: "newLessonform"} do |f| %>
<%= f.input :title, label: "Lesson Title", required: false %>
<%= f.input :description, required: false, as: :text %>
<%= f.input :points, required: false, as: :integer %>
<%= f.input :is_public, label: 'Check to Make this lesson public', as: :boolean %>
<div class="col-md-12">
<% unless #lesson.new_record? or #lesson.active_video_url.blank? %>
<h4> Currently Linked Video </h4>
<video src="<%= #lesson.active_video_url %>" style="width: 400px;"></video>
<% end %>
<hr/>
</div>
<h4>Add <%= #lesson.videos.blank? ? "a" : "another" %> Video</h4>
<% #lesson.videos = [Video.new(title: "")] if #lesson.videos.blank? %>
<%= f.simple_fields_for :videos do |g| %>
<%= g.input :title, label: "Video title" %>
<%= g.input :video, as: :file, lebel: "Select Video" %>
<% end %>
<center><%= f.submit class: "lesson-category btn-danger" %></center>
<% end %>
</div>
<script type="text/javascript">
$(".newLessonform").ajaxForm(function(data) {
$("#primaryModalContent").html(data.message);
});
</script>
In the above script , I have given ajaxForm. The modal form for this is given below.
<div class="modal fade" id="primaryModal" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" , data-dismiss="modal">×</button>
<h1 class="modal-title" id="modalTitle"></h1>
</div>
<div class="row modal-body" id="primaryModalContent">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
The error in chrome console , was uncaught error:(...)$.ajaxForm is not a function.
I am stuck in this for about a week. Could any one give me a solution.
Thanks in advance.
The best way to use an AJAX form in rails is to use rails_ujs.
First you have to tell rails_ujs that you want an AJAX action on your form :
<%= simple_form_for #lesson, html: {class: "newLessonform"}, remote: true do |f| %>
Then add a new file in your views, this view will be rendered after a successfull create action initiated by an AJAX action : views/lessons/create.js.erb
Inside you can put you js code, this code will be executed on the same page as the AJAX form. This is just a view and you can use variables from the controller.
$("#primaryModalContent").html("<%= #message %>")
Finally, you need to update your controller to handle AJAX action :
def create
#lesson = Lesson.new(lesson_params)
if #lesson.save
#success = true
#message = "Lesson Created Successfully"
else
#success = false,
#message = "Lesson Creation Failed"
end
respond_to do |format|
format.js
end
end
Here you can find some documentation about Rails UJS :
http://guides.rubyonrails.org/working_with_javascript_in_rails.html#remote-elements
https://blog.codeship.com/unobtrusive-javascript-via-ajax-rails/

Rails: Submit html table content in form to controller

I have some trouble with an rails formular.
I have a form to create "projects".
Project form
<%= bootstrap_form_for(#project) do |f| %>
...
<div class="container-fluid">
<%= f.static_control label:"Vordefinierte Aufgaben" do %>
<div class="actions form-group nopadding">
<div class="center-block">
<%=link_to "", data: {toggle:"modal", target:".newTask-modal"} , class: "btn btn-success center-block btn-sidebar-ok", id: "singlebutton" do%>
<i> <span class="glyphicon glyphicon-plus pull-left btn-sidebar-icon"></span>Neue Aufgabe hinzufügen </i>
<% end %>
</div>
</div>
<div class="task-table">
<%=render 'tasks/table'%>
</div>
<% end %>
</div>
...
<!-- task Modal to create a new task -->
<%=render 'tasks/newTaskModal' %>
<% end %>
<!-- Button -->
<div class="actions form-group">
<div class="center-block">
<%= button_tag( type: 'submit', class: "btn btn-success center-block btn-sidebar-ok", id: "singlebutton") do%>
<i> <span class="glyphicon glyphicon-ok pull-left"></span>Projekt anlegen </i>
<% end %>
</div>
</div>
Within this form a have a table which shows created tasks and a button to open an bootstrap modal. This modal contains a new form to create a task.
Task Form within modal
<%= bootstrap_form_tag() do |f| %>
<div class="col-sm-8">
<%= f.text_field :task_title, label: "Titel", placeholder: "Betreff", icon: "pencil",wrapper: { class: 'icon-addon addon-md'} %>
</div>
<div class="col-sm-4">
<%= f.number_field :task_in_min, label: "Arbeitszeit in Min", placeholder: "Bsp.: 25", icon: "time", wrapper: { class: 'icon-addon addon-md'}%>
</div>
<div class="col-sm-12">
<%= f.text_area :task_description, label: "Beschreibung*", placeholder: "Aufgabenbeschreibung", icon: "pencil", rows: 10, wrapper: { class: 'icon-addon addon-md'}%>
</div>
<%= button_tag( type: 'button', id:"taskSubmit", class: "btn btn-success center-block btn-sidebar-ok") do %>
<i > <span class="glyphicon glyphicon-ok pull-left btn-sidebar-icon"></span> Speichern </i>
<% end %>
<% end %>
If I click to "taskSubmit" a javascript put this task (title, description, min) into the table within the project form. JS create a new table row with the task content.
Javascript
//take data from task form and at a new task element to the task table in project form
$(function TaskSubmitFunction(){
$('#taskSubmit').click(function(){
var task_title = $('#task_title').val();
var task_description = $('#task_description').val();
var task_in_min = $('#task_in_min').val();
//Remove spaces from title
var id = task_title.replace(/ /g,'');
$('#taskTable tr:last').after('<tr id="task_'+id+'"> <td>'+task_title+'</td> <td>'+task_description+'</td><td>'+task_in_min+'</td><td> <span class="pull-right"><span data-toggle="tooltip" data-placement="right" data-original-title="Löschen"><button class="btn btn-sm btn-danger btn-colored delete-position" id="'+id+'"name="button" type="button" task="'+task_title+'"><i><span class="glyphicon glyphicon-remove"/></i></button></span></span></td></tr>');
$('#taskTable').after('<input type="hidden" id="1" name="1" value="'+task_title+'" />');
$('#task_title').val('');
$('#task_description').val('');
$('#task_in_min').val('');
//initialize task delete
$(function TaskDeleteFunction(){
$('#'+id).click(function(){
var task_title = $(this).attr('task');
if (confirm("Soll die Aufgabe wirklich gelöscht werden?")) {
$('#'+id).remove();
}
return false;
});
});
});
});
What I want to do now is to submit these table elements to the project controller to create the project and all necessary tasks activeRecords. Is this possible?
How can I do this? Maybe create a hidden field for every table element which will be submit to the project form? But every table element consists of three values... how can I do this?
Do you have any idea?
best regards
Why not just use three hidden fields (one for each value)? Straightforward and they will be easy to access in the params hash.

How to hide/show back/next button with JavaScript in a Rails from wizard?

I've created a wizard form with this gem: https://github.com/stephenbaldwin/fuelux-rails
Everything is working in terms of getting to the next and previous steps. However, what's a 'rails way' to hide the 'prev' button on first step and show only the 'submit' button on last step? Is this something I'd do do in js?
_form.html.erb
<%= form_for(#wizard) do |f| %>
<div>
<div id="MyWizard" class="wizard">
<ul class="steps">
<li data-target="#step1" class="active"><span class="badge badge-info">1</span>Step 1<span class="chevron"></span></li>
<li data-target="#step2"><span class="badge">2</span>Step 2<span class="chevron"></span></li>
<li data-target="#step3"><span class="badge">3</span>Step 3<span class="chevron"></span></li>
</ul>
</div>
<div class="step-content">
<div class="step-pane active" id="step1">
<div class="field">
<%= f.label :field1 %><br />
<%= f.text_field :field1 %>
</div>
</div>
<div class="step-pane" id="step2">
<div class="field">
<%= f.label :field2 %><br />
<%= f.text_field :field2 %>
</div>
</div>
<div class="step-pane" id="step3">
<div class="field">
<%= f.label :field3 %><br />
<%= f.text_field :field3 %>
</div>
</div>
<input type="button" class="btn btn-mini" id="btnWizardPrev" value="prev">
<input type="button" class="btn btn-mini" id="btnWizardNext" value="next"></br>
<div>
<%= f.submit :class => 'btn btn-mini btn-primary' %>
</div>
</div>
</div>
<% end %>
application.js file:
$(function() {
$('#MyWizard').on('change', function(e, data) {
console.log('change');
if(data.step===3 && data.direction==='next') {
// return e.preventDefault();
}
});
$('#MyWizard').on('changed', function(e, data) {
console.log('changed');
});
$('#MyWizard').on('finished', function(e, data) {
console.log('finished');
});
$('#btnWizardPrev').on('click', function() {
$('#MyWizard').wizard('previous');
});
$('#btnWizardNext').on('click', function() {
$('#MyWizard').wizard('next','foo');
});
$('#btnWizardStep').on('click', function() {
var item = $('#MyWizard').wizard('selectedItem');
console.log(item.step);
});
});
Side note/question - is there a way to put this .js in my asset pipeline without storing it in application.js? I tried to create a separate .js under javascripts but it dosen't pull in.
In your javascript file replace this block
$('#MyWizard').on('change', function(e, data) {
console.log('change');
if(data.step===3 && data.direction==='next') {
// return e.preventDefault();
}
});
with following block: (UPDATED)
$('#MyWizard').on('change', function(e, data) {
console.log('change');
$('#wizard-submit').hide(); //hide the submit button on each step.
if(data.step === 3 && data.direction === 'next') {
// return e.preventDefault();
$('#wizard-submit').show(); //show the submit button only on last(3rd in your case) step.
}
switch(data.step) {
case 1:
if(data.direction === 'next')
$('#btnWizardPrev').show();
else
$('#btnWizardPrev').hide();
$('#btnWizardNext').show();
break;
case 2:
if(data.direction === 'next') {
$('#btnWizardPrev').show();
$('#btnWizardNext').hide();
}
else {
$('#btnWizardPrev').hide();
$('#btnWizardNext').show();
}
break;
case 3:
// I would recommend to show the prev button on last step but hide the next button.
if(data.direction === 'next')
$('#btnWizardNext').hide();
else
$('#btnWizardNext').show();
$('#btnWizardPrev').show();
break;
default:
$('#btnWizardPrev').show();
$('#btnWizardNext').show();
}
});
The above code will show/hide the buttons based on the step you're in.
And for you second question: are you specifying the //= require_tree . in the application.js. If yes then try enclosing the code in $(document).ready(function(){..code goes here..})
UPDATE See the updated code above. I am not sure if this is the correct way, but I am able to get it working this way.
Also add #btnWizardPrev { display: none; }
Assumption: There are three steps in the form. If there are more you would need to add more cases in switch statement. Basically you'll need to break the case 2: statement in that case. In case 2: the next condition is for removing the next button, so in case there are more steps, move the next condition to second last step.
UPDATE Replace your submit button code with <%= f.submit :class => 'btn btn-mini btn-primary', :id => 'wizard-submit' %>. This will simply add id attribute to your submit button. You can use any value to be its id. Then just hide the submit button by adding this css #wizard-submit { dispay: none } and then use the above updated jquery code in your javascript file.
The wizard plugin already disables the previous button on the first step. It looks for a button.btn-prev located in the wizard container
<div id="myWizard" class="wizard">
<div class="actions">
<button class="btn btn-mini btn-prev"> <i class="icon-arrow-left"></i>Prev</button>
<button class="btn btn-mini btn-next" data-last="Finish">Next<i class="icon-arrow-right"></i></button>
</div>
If you'd like to hide the disabled previous button you could target it with css to avoid javascript
.wizard button.btn-prev[disabled] {
display: none;
}

Categories

Resources