Ajax Single Field Submission in form - ruby-on-rails

I've created an order form, of which has a large array of fields. I'm now adding coupon functionality so that we can start to give customers discount codes etc.
What's the best way of submitting a single field (the coupon code) using ajax after a "apply coupon" button has been clicked so that the price can be updated on the front end probably using UJS(?) - obviously the final price calculation would happen on the backend?
Cheers.

I would recommend using a JS framework to do Ajax requests. If you JQuery, then you can use the example given to understand how to do a simple post.
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
<form action="/" id="searchForm">
<input type="text" name="s" placeholder="Search..." />
<input type="submit" value="Search" />
</form>
<!-- the result of the search will be rendered inside this div -->
<div id="result"></div>
<script>
/* attach a submit handler to the form */
$("#searchForm").submit(function(event) {
/* stop form from submitting normally */
event.preventDefault();
/* get some values from elements on the page: */
var $form = $( this ),
term = $form.find( 'input[name="s"]' ).val(),
url = $form.attr( 'action' );
/* Send the data using post and put the results in a div */
$.post( url, { s: term },
function( data ) {
var content = $( data ).find( '#content' );
$( "#result" ).empty().append( content );
}
);
});
</script>
</body>
</html>

Related

DirtyForms does not work properly with $.blockUI

I'm using DirtyForms and $.blockUI plugin, the latter to change pages when clicking on links (in my app, some pages take a couple of seconds more to load and a visual feedback is fine).
When I change field content and then click any link, DirtyForms is triggered: but when I cancel the process to stay on the page, $.blockUI starts its game, resulting in a stuck page
$('form[method="post"]').dirtyForms();
$('a').on('click', function(){
$.blockUI();
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.dirtyforms/2.0.0/jquery.dirtyforms.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.blockUI/2.70/jquery.blockUI.min.js"></script>
<p>Change the field content to activate DirtyForms, then click on the link.<br>
When the popup appears, click on "cancel" to stay on the page.<br>
Watch blockUI getting fired as the link is going to be followed</p>
<form action="#" method="post">
<input type="text" name="username" required>
<button type="submit">send</button>
</form>
click me after changing field content
Please, any solution?
EDIT: I also tried with stay.dirtyforms and afterstay.dirtyforms events, but they have no effect. defer.dirtyforms seems to work but the event is triggered twice (I put a console.log() to check) and I am not sure this is the way to go...
I've edit my answer: I've added some line of code to disable first the onbeforeunload dialog alert, taken from here. And at the end a link to an answer with another idea you can try.
My idea: you have to prevent the default link action and use the $.blockUI Modal Dialogs methods to open a custom dialog, then catch the link attribute href from the link put it inside a variable and use the variable value for the #yes button of the dialog.
See if this solution can meet your needs
/* beforeunload bind and unbind taken from https://gist.github.com/woss/3c2296d9e67e9b91292d */
// call this to restore 'onbeforeunload'
var windowReloadBind = function(message) {
window.onbeforeunload = function(event) {
if (message.length === 0) {
message = '';
};
if (typeof event == 'undefined') {
event = window.event;
};
if (event) {
event.returnValue = message;
};
return message;
}
};
// call this to prevent 'onbeforeunload' dialog
var windowReloadUnBind = function() {
window.onbeforeunload = function() {
return null;
};
};
var linkToFollow; // href to follow
$('form[method="post"]').dirtyForms();
$('a').on('click', function(e){
e.preventDefault();
windowReloadUnBind(); // prevent dialog
$.blockUI({ message: $('#question'), css: { width: '275px' } });
linkToFollow = $(this).attr('href');
});
$('#no').click(function() {
$.unblockUI();
return false;
});
$('#yes').click(function() {
$(window.location).attr('href', linkToFollow);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.dirtyforms/2.0.0/jquery.dirtyforms.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.blockUI/2.70/jquery.blockUI.min.js"></script>
<p>Change the field content to activate DirtyForms, then click on the link.<br>
When the popup appears, click on "cancel" to stay on the page.<br>
Watch blockUI getting fired as the link is going to be followed</p>
<form action="#" method="post">
<input type="text" name="username" required>
<button type="submit">send</button>
</form>
click me after changing field content
<div id="question" style="display:none; cursor: default">
<h6>Would you like to contine?.</h6>
<input type="button" id="yes" value="Yes" />
<input type="button" id="no" value="No" />
</div>
Other idea taken from another answer: Other idea would be to make a simple jQuery.ajax({}) call before return value in beforeunload as seen in this answer

Browser History entry when POST form to to iframe with javascript (IE)

Basically i want to automatically POST content to a form without using XMLHttpRequest.
The site works fine but there is a problem with the browser history when getting back to the page by clicking the browser back button.
My site looks like this:
<!DOCTYPE html>
<html>
<head runat="server">
<title>History Problem</title>
<script>
window.onload = function () {
try {
if ("<%= Request.Form["hiddenField1"] == null %>" == "True") {
var theForm = document.getElementById("myForm");
var theIframe = document.createElement('iframe');
theIframe.id = theIframe.name = "myIframe";
document.body.appendChild(theIframe);
theForm.hiddenField1.value = "SomeValue";
theForm.submit();
}
}
catch (e) {
var x = e;
}
};
window.onunload = function () { };
</script>
</head>
<body>
<form runat="server" id="myForm" action="" target="myIframe" method="post">
<input type="hidden" id="hiddenField1" name="hiddenField1" />
</form>
<br />
External Link
</body>
</html>
The trace shows that there is a GET and a POST request. everything is fine so far. But if you click on "External Link" (google.com) and then back to the site, you'll see two history entries for the test site. Also the google.com history entry seems to be gone.
This happens only in Internet Explorer.
Any ideas?

DatePicker Jquery API can to load in Liferay JSP

I was trying to load Datepicker so that I can later add the value to json request. But it seems that I can't even load the calender in textbox. Idea is to get input date and request it in json.
Well I could mention that without datepicker function it was working fine.
// Portlet JSP in Liferay
<%# taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>
<portlet:resourceURL var="resourceURL">
</portlet:resourceURL>
<portlet:defineObjects />
// jQuery UI sources
<link rel="stylesheet"
href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
// Jquery and Ajax Source
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js">
</script>
// JS Function
<script>
$(document).ready(function() {
// Load Date Picker in input box But not working
$( "#datepicker" ).datepicker();
$("#btn").click(function() {
$.ajax({
// Reso
url : '${resourceURL}',
data : {
"PersonID" : $('#PersonID').val(),
"AnotherD" : 2
},//person id to sent, In place of Anotherd I want to add Datevalue
type : 'POST',
dataType : "json",
success : function(data) {
console.log(data);
//Getting Data in return
var x = data.PersonList[1].PersonWeight;
$("#Results").text(x);
$("#Res").text(data.PersonList[1].PersonTemp);
}
});
});
});
</script>
<body>
// Out Put Data
PersonID:
<input type="text" name="PersonID" id="PersonID">
<br>
// Date Picker Textbox
<br>
<p>
Date: <input type="text" id="datepicker" />
</p>
// Refresh Button
<button id="btn">Refresh</button>
<br>Height :
<p id="Results"></p>
<br> Weight:
<p id="Res"></p>
</body>
But its not working, any suggestions?
Remove this line. I think jQuery conflicts is occurring in your case
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js">
</script>
HTH

Select all checkboxes

In my Rails app I've created a set of checkboxes as follows:
<div class="form_row">
<label for="features[]">Features:</label>
<% ['scenarios', 'news', 'role_profiles', 'private_messages', 'chatrooms', 'forums', 'polls'].each do |feature| %>
<br><%= check_box_tag 'features[]', feature, (#features || {}).include?(feature) %>
<%= feature.humanize %>
<% end %>
</div>
I'd like to know how to create a button that would "Select All".
Using jQuery;
<script type="text/javascript">
function selectAll(){
$("input:checkbox").each(function(){
$(this).attr('checked', true);
});
return false;
}
</script>
HTML button:
Select All
If you use the Prototype JS, you might find this blog post helpful. It gives a fairly concise way to perform a select all.
http://www.ryboe.com/2008/07/10/select-all-checkboxes-with-prototype-js.html
In your view you could use the following snippet to create a "Select All" link:
<%= link_to_function("Select All","checkboxes.each(function(e){ e.checked = 1 })") %>
In addition, you'd need the following Javascript code somewhere on the same page (or maybe even abstracted out to the public/javascripts/application.js file
var checkboxes = [];
checkboxes = $$('input').each(function(e){ if(e.type == 'checkbox') checkboxes.push(e) });
var form = $('options'); /* Replace 'options' with the ID of the FORM element */
checkboxes = form.getInputs('checkbox');
Here's the full source of a working example, if this doesn't work you might need to check to make sure your JS libraries are loading properly.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script type="text/javascript" src="http://www.google.com/jsapi" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
var checkboxes;
google.load("prototype", "1.6");
google.setOnLoadCallback(function(){
checkboxes = [];
checkboxes = $$('input').each(function(e){ if(e.type == 'checkbox') checkboxes.push(e) });
var form = $('options'); /* Replace 'options' with the ID of the FORM element */
checkboxes = form.getInputs('checkbox');
});
</script>
</head>
<body>
<form id="options">
<fieldset><input type="text" value="test"></fieldset>
<fieldset><input type="checkbox" value=0> 0</fieldset>
<fieldset><input type="checkbox" value=1> 1</fieldset>
<fieldset><input type="checkbox" value=2> 2</fieldset>
<fieldset><input type="checkbox" value=3> 3</fieldset>
</form>
Select All
</body>
</html>
I think you can use query like that
<script>
$('#check_all').on("click", function(){
var check = $('input[type="checkbox"]');
check.prop("checked", !check.prop("checked"));
});
</script>
and the html will be something like
<%= button_tag 'select / unselect all', id: 'check_all', class:'b' %>

How do you post to an iframe?

How do you post data to an iframe?
Depends what you mean by "post data". You can use the HTML target="" attribute on a <form /> tag, so it could be as simple as:
<form action="do_stuff.aspx" method="post" target="my_iframe">
<input type="submit" value="Do Stuff!">
</form>
<!-- when the form is submitted, the server response will appear in this iframe -->
<iframe name="my_iframe" src="not_submitted_yet.aspx"></iframe>
If that's not it, or you're after something more complex, please edit your question to include more detail.
There is a known bug with Internet Explorer that only occurs when you're dynamically creating your iframes, etc. using Javascript (there's a work-around here), but if you're using ordinary HTML markup, you're fine. The target attribute and frame names isn't some clever ninja hack; although it was deprecated (and therefore won't validate) in HTML 4 Strict or XHTML 1 Strict, it's been part of HTML since 3.2, it's formally part of HTML5, and it works in just about every browser since Netscape 3.
I have verified this behaviour as working with XHTML 1 Strict, XHTML 1 Transitional, HTML 4 Strict and in "quirks mode" with no DOCTYPE specified, and it works in all cases using Internet Explorer 7.0.5730.13. My test case consist of two files, using classic ASP on IIS 6; they're reproduced here in full so you can verify this behaviour for yourself.
default.asp
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>Form Iframe Demo</title>
</head>
<body>
<form action="do_stuff.asp" method="post" target="my_frame">
<input type="text" name="someText" value="Some Text">
<input type="submit">
</form>
<iframe name="my_frame" src="do_stuff.asp">
</iframe>
</body>
</html>
do_stuff.asp
<%#Language="JScript"%><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>Form Iframe Demo</title>
</head>
<body>
<% if (Request.Form.Count) { %>
You typed: <%=Request.Form("someText").Item%>
<% } else { %>
(not submitted)
<% } %>
</body>
</html>
I would be very interested to hear of any browser that doesn't run these examples correctly.
An iframe is used to embed another document inside a html page.
If the form is to be submitted to an iframe within the form page, then it can be easily acheived using the target attribute of the tag.
Set the target attribute of the form to the name of the iframe tag.
<form action="action" method="post" target="output_frame">
<!-- input elements here -->
</form>
<iframe name="output_frame" src="" id="output_frame" width="XX" height="YY">
</iframe>
Advanced iframe target use
This property can also be used to produce an ajax like experience, especially in cases like file upload, in which case where it becomes mandatory to submit the form, in order to upload the files
The iframe can be set to a width and height of 0, and the form can be submitted with the target set to the iframe, and a loading dialog opened before submitting the form. So, it mocks a ajax control as the control still remains on the input form jsp, with the loading dialog open.
Exmaple
<script>
$( "#uploadDialog" ).dialog({ autoOpen: false, modal: true, closeOnEscape: false,
open: function(event, ui) { jQuery('.ui-dialog-titlebar-close').hide(); } });
function startUpload()
{
$("#uploadDialog").dialog("open");
}
function stopUpload()
{
$("#uploadDialog").dialog("close");
}
</script>
<div id="uploadDialog" title="Please Wait!!!">
<center>
<img src="/imagePath/loading.gif" width="100" height="100"/>
<br/>
Loading Details...
</center>
</div>
<FORM ENCTYPE="multipart/form-data" ACTION="Action" METHOD="POST" target="upload_target" onsubmit="startUpload()">
<!-- input file elements here-->
</FORM>
<iframe id="upload_target" name="upload_target" src="#" style="width:0;height:0;border:0px solid #fff;" onload="stopUpload()">
</iframe>
This function creates a temporary form, then send data using jQuery :
function postToIframe(data,url,target){
$('body').append('<form action="'+url+'" method="post" target="'+target+'" id="postToIframe"></form>');
$.each(data,function(n,v){
$('#postToIframe').append('<input type="hidden" name="'+n+'" value="'+v+'" />');
});
$('#postToIframe').submit().remove();
}
target is the 'name' attr of the target iFrame, and data is a JS object :
data={last_name:'Smith',first_name:'John'}
If you want to change inputs in an iframe then submit the form from that iframe, do this
...
var el = document.getElementById('targetFrame');
var doc, frame_win = getIframeWindow(el); // getIframeWindow is defined below
if (frame_win) {
doc = (window.contentDocument || window.document);
}
if (doc) {
doc.forms[0].someInputName.value = someValue;
...
doc.forms[0].submit();
}
...
Normally, you can only do this if the page in the iframe is from the same origin, but you can start Chrome in a debug mode to disregard the same origin policy and test this on any page.
function getIframeWindow(iframe_object) {
var doc;
if (iframe_object.contentWindow) {
return iframe_object.contentWindow;
}
if (iframe_object.window) {
return iframe_object.window;
}
if (!doc && iframe_object.contentDocument) {
doc = iframe_object.contentDocument;
}
if (!doc && iframe_object.document) {
doc = iframe_object.document;
}
if (doc && doc.defaultView) {
return doc.defaultView;
}
if (doc && doc.parentWindow) {
return doc.parentWindow;
}
return undefined;
}
You can use this code, will have to add proper params to be passed and also the api url to get the data.
var allParams = { xyz, abc }
var parentElm = document.getElementBy... // your own element where you want to create the iframe
// create an iframe
var addIframe = document.createElement('iframe');
addIframe.setAttribute('name', 'sample-iframe');
addIframe.style.height = height ? height : "360px";
addIframe.style.width = width ? width : "360px";
parentElm.appendChild(addIframe)
// make an post request
var form, input;
form = document.createElement("form");
form.action = 'example.com';
form.method = "post";
form.target = "sample-iframe";
Object.keys(allParams).forEach(function (elm) {
console.log('elm: ', elm, allParams[elm]);
input = document.createElement("input");
input.name = elm;
input.value = allParams[elm];
input.type = "hidden";
form.appendChild(input);
})
parentElm.appendChild(form);
form.submit();

Resources