Easiest way of converting a regular from to perform submissions via ajax? - ajax

I'm trying to convert simple forms such as:
<form action="/api.php", method="get">
... radios, checkboxes etc
<input type="submit" value="Submit">
</form>
To perform ajax submission instead of reloading the page when hitting submit using angular.
I plan on removing the submit button and replacing it with a regular button with ng-click="submit()". My submit function would look something like this:
$scope.submit = function() {
$http.get('/api', { params: ??? })
.success(...));
}
However the difficulty I have here is attaching the get params from my form inputs. I'm not sure how to reference them. Would I have to add ng-model to every single input element?
I have a lot of forms that require "converting" and I was wondering what would be the least intrusive way (least changes to markup) to do this? The reason is because a previous developer has left me with a soup of ugly html changing things will be costly.

Yes, its EASY.
html
<form action="/api.php" ng-submit="submit()">
<input type="text" name="name" ng-model="user.name">
<input type="submit" value="Submit">
</form>
js
$scope.submit = function() {
$scope.user = {};
$http({
method: 'GET',
url: '/api.php?name=' + $scope.user.name
}).
success(function(data, status, headers, config) {
console.log(JSON.stringify(data));
});
};

Related

I can't send file through an ajax PUT request, using Laravel

I have a form with an input of type file hidden. An image tag works as the clickable trigger to select the file itself, with js to trigger it (that works), but I want to automatically make a PUT request as one chooses an image instead of having to click a submit button on the form, every time the image is changed on the input field. I'm using ajax for that, but at the controller endpoint that processes the request, I don't seem to have any file. If I put other fields such as textual they seem to pass into the controller through the request just fine, though.
My route:
Route::put('/coins/image/{key}', [CoinController::class, 'image'])->name("coins.image");
My controller (no actual image-updating code yet; just what I'm doing to check for the file):
public function image(int $key)
{
dump(request()->file('file'));
dump(request()->file);
dump(request());
}
My HTML and JS in the following snippet:
function promptImageForUpload(elemId)
{
$('#' + elemId).click();
}
function uploadImage(event, imgId, key)
{
event.preventDefault();
var inputElem = event.target;
var imageFile = inputElem.files[0];
var imgElem = $('#' + imgId);
var form = $(inputElem).parent();
var formData = new FormData(form[0]);
formData.append('file', imageFile);
$.ajax({
url: "/coins/image/" + key,
type: "PUT",
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
data: formData,
enctype: 'multipart/form-data',
processData: false,
contentType: false,
success: function(response) {
var reader = new FileReader();
reader.onload = function(e) {
imgElem.attr("src", e.target.result);
};
reader.readAsDataURL(imageFile); // convert to base64 string
}
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="card-body">
<form data-key="0" id="coin-header-0_form" method="POST" action="#" enctype="multipart/form-data">
<input type="file" name="file" id="coin-header-0_file" style="z-index:-1; width: 100%; height: 100%; display: none;" onchange="uploadImage(event, 'coin-header-0_preview', 0)">
<input type="hidden" name="_method" value="PUT">
<meta name="csrf-token" content="7c3s2NmosdK9qzrS10xGAB0rYXw5g41azRjcmPQC">
<img src="http://snapbuilder.com/code_snippet_generator/image_placeholder_generator/60x40/007730/DDDDDD/this%20pict" width="50px" height="50px" alt="icon" id="coin-header-0_preview" onclick="promptImageForUpload('coin-header-0_file');">
</form>
</div>
For now, I am force-updating the preview of the image on the ajax success instead of retrieving it from the updated entity upon successful update, to avoid a second query.
I have the method set to PUT for spoofing in the ajax request and the xsrf token set the headers as well.
Enctype is set to multipart/form-data for files too. I have no clue as to why I don't see the uploaded file anywhere in the request.
Using Laravel Framework 8.25.0, jquery 3.5.1.
Please let me know if any more info is needed, anyone.
I couldn't find any solution on any stackoverflow entry or elsewhere that regards this subject.
Any help is greatly appreciated since I don't really how else to look at this in a debugging approach.
HTML forms do not support PUT, PATCH or DELETE actions. So, when defining PUT, PATCH or DELETE routes that are called from an HTML form, you will need to add a hidden _method field to the form. The value sent with the _method field will be used as the HTTP request method:
<form action="/foo/bar" method="POST">
<input type="hidden" name="_method" value="PUT">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>
You may use the method_field helper to generate the _method input:
{{ method_field('PUT') }}
In the same way, this check may also affect ajax forms. Then in your form switch to the POST method and set the PUT parameter for it to work.

Play framework write Action with Ok(...) that doesn't load new page

Play framework 2.4.x. A button is pressed on my home page that executes some code via Ajax, and returns its results beneath the button without loading a new page. The results wait for a user to input some text in a field and press "submit". Those results Look like this:
<li class="item">
<div>
<h3>Email: </h3>
<a>#email.tail.init</a>
<h3>Name: </h3>
<a>#name</a>
</div>
<div>
<h3>Linkedin: </h3>
<form class="linkedinForm" action="#routes.Application.createLinkedin" method="POST">
<input type="number" class="id" name="id" value="#id" readonly>
<input type="text" class="email" name="email" value="#email" />
<input type="text" class="emailsecondary" name="emailsecondary" value="" />
<input type="text" class="name" name="email" value="#name" />
<input type="text" class="linkedin" name="linkedin" value="" />
<input type="submit" value="submit" class="hideme"/>
</form>
</div>
<div>
<form action="#routes.Application.delete(id)" method="POST">
<input type="submit" value="delete" />
</form>
</div>
</li>
Along with some jquery that slides up a li after submission:
$(document).ready(function(){
$(".hideme").click(function(){
$(this).closest('li.item').slideUp();
});
});
However, since a form POST goes inside an Action that must a return an Ok(...) or Redirect(...) I can't get the page to not reload or redirect. Right now my Action looks like this (which doesn't compile):
newLinkedinForm.bindFromRequest.fold(
errors => {
Ok("didnt work" +errors)
},
linkedin => {
addLinkedin(linkedin.id, linkedin.url, linkedin.email, linkedin.emailsecondary, linkedin.name)
if (checkURL(linkedin.url)) {
linkedinParse ! Linkedin(linkedin.id, linkedin.url, linkedin.email, linkedin.emailsecondary, linkedin.name)
Ok(views.html.index)
}else{
Ok(views.html.index)
}
}
)
Is it possible to return Ok(...) without redirecting or reloading? If not how would you do a form POST while staying on the same page?
EDIT: Here is my attempt at handling form submission with jquery so far:
$(document).ready(function(){
$(".linkedinForm").submit(function( event ) {
var formData = {
'id' : $('input[name=id]').val(),
'name' : $('input[name=name]').val(),
'email' : $('input[name=email']).val(),
'emailsecondary' : $('input[name=emailsecondary]').val(),
'url' : $('input[name=url]').val()
};
jsRoutes.controllers.Application.createLinkedin.ajax({
type :'POST',
data : formData
})
.done(function(data) {
console.log(data);
});
.fail(function(data) {
console.log(data);
});
event.preventDefault();
};
});
This is an issue with the browser's behavior on form submission, not any of Play's doing. You can get around it by changing the behavior of the form when the user clicks submit.
You will first want to attach a listener to the form's submission. You can use jQuery for this. Then, in that handler, post the data yourself and call .preventDefault() on the event. Since your javascript is now in charge of the POST, you can process the data yourself and update your page's HTML rather than reloading the page.
What you need is use ajax to submit a form, check this: Submitting HTML form using Jquery AJAX
In your case, you can get the form object via var form = $(this), and then start a ajax with data from the form by form.serialize()
$.ajax({
type: form.attr('method'),
url: form.attr('action'),
data: form.serialize(),
success: function (data) {
alert('ok');
}
});
In order to accomplish this task, i had to use play's javascriptRouting
This question's answer helped a lot.
I'm not experienced with jquery so writing that correctly was difficult. For those that find this, here is my final jquery that worked:
$(document).ready(function(){
$("div#results").on("click", ".hideme", function(event) {
var $form = $(this).closest("form");
var id = $form.find("input[name='id']").val();
var name = $form.find("input[name='name']").val();
var email = $form.find("input[name='email']").val();
var emailsecondary = $form.find("input[name='emailsecondary']").val();
var url = $form.find("input[name='url']").val();
$.ajax(jsRoutes.controllers.Application.createLinkedin(id, name, email, emailsecondary, url))
.done(function(data) {
console.log(data);
$form.closest('li.item').slideUp()
})
.fail(function(data) {
console.log(data);
});
});
});
Note that my submit button was class="hideme", the div that gets filled with results from the DB was div#results and the forms were contained within li's that were class="item". So what this jquery is doing is attaching a listener to the static div that is always there:
<div id="results">
It waits for an element with class="hideme" to get clicked. When it gets clicked it grabs the data from the closest form element then sends that data to my controller via ajax. If the send is successful, it takes that form, looks for the closest li and does a .slideUp()
Hope this helps

Automate AJAXed forms with Jquery

I want to improve my website and figured out a good way to do it was by submitting forms via AJAX. But, I have so many forms that it would be inpractical to do $('#formx').submit(). I was wondering if there was a way to do this automatically by making an universal markup like;
<form class="ajax_form" meta-submit="ajax/pagename.php">
<input type="text" name="inputx" value="x_value">
<input type="text" name="inputy" value="y_value">
</form>
And have this submit to ajax/pagename.php, where it automatically includes inputx and inputy?
This would not only save me a lot of time but also a lot of lines of code to be written.
First question so I hope it's not a stupid one :)
Something like this should work for all forms. It uses jQuery - is this available in your project? This specific code chunk hasn't been tested per say, but I use this method all the time. It is a wonderful time saver. Notice I changed meta-submit to data-submit so that its value can be fetched using $('.elemenet_class').data('submit');
HTML
<!-- NOTE: All Form items must have a unique 'name' attribute -->
<form action="javascript:void(0);" class="ajax_form" data-submit="ajax/pagename.php">
<input type="text" name="inputx" value="x_value">
<input type="text" name="inputy" value="y_value">
<input type="submit" value="go" />
</form>
JavaScript
$('.ajax_form').submit(function(e){
var path = $(this).attr('data-submit'); //Path to Action
var data = $(this).serialize(); //Form Data
$.post(path, {data:data}, function(obj){
});
return false;
})
PHP
//DEBUGGING CODE
//var_dump($_POST);
//die(null);
$data = $_POST['data'];
$inputx = $data['inputx'];
$inputy = $data['inputy'];
you can create ajax fot text boxes so that it can update to database whenever change the focus from it.
<form id="ajax_form1">
<fieldset>
<input type="text" id="inputx" value="x_value" />
<input type="text" id="inputy" value="y_value" />
</fieldset>
</form>
<script>
$(document).ready(function()
{
$("form#ajax_form1").find(":input").change(function()
{
var field_name=$(this).attr("id");
var field_val=$(this).val();
var params ={ param1:field_name, param2:field_val };
$.ajax({ url: "ajax/pagename.php",
dataType: "json",
data: params,
success: setResult
});
});
});
</script>

jQuery Mobile avoid changePage() in ajax form submit

I have a post form, I want the submit to be done in an AJAX way but I don't want the page URL to change.
For example:
<form action="/countries/change_country" data-ajax="true" method="post">
<select name="country_code">
<option value="FR" selected="selected">France</option>
<option value="DE">Germany</option>
</select>
<input type="submit" value="change country" />
</form>
When I click in the change country button the form is sent through AJAX what is nice but the page URL is changed to /countries/change_country what is not nice because this URL doesn't exist in my server which is very picky with HTTP verbs.
I know it is possible to change this default behavior for the whole application but I would like to deactivate the changePage() only for this form.
Submit the form through Javascript/jQuery instead.
First: Disable the default submit-behaviour
$('#form').on('submit', function (e) {
if (e.preventDefault) e.preventDefault();
return false;
});
Second: Serialize the form data with jQuery
var serializedFormData = $('#form').serialize();
Third: Post your form with $.ajax();
$.ajax({
url: '/countries/change_country',
type: 'POST',
data: serializedFormData
});

Load Dojo form from ajax call

I am trying to implement something like this.
http://app.maqetta.org/mixloginstatic/LoginWindow.html
I want the login page to load but if you click the signup button then an ajax will replace the login form with the signup form.
I have got this to work using this code
dojo.xhrGet({
// The URL of the request
url: "'.$url.'",
// The success callback with result from server
load: function(newContent) {
dojo.byId("'.$contentNode.'").innerHTML = newContent;
},
// The error handler
error: function() {
// Do nothing -- keep old content there
}
});'
the only problem is the new form just loads up as a normal form, not a dojo form. I have tried to return some script with the phaser but it doesnt do anything.
<div id="loginBox"><div class="instructionBox">Please enter your details below and click <a><strong>signup</strong>
</a> to have an activation email sent to you.</div>
<form enctype="application/x-www-form-urlencoded" class="site-form login-form" action="/user/signup" method="post"><div>
<dt id="emailaddress-label"><label for="emailaddress" class="required">Email address</label></dt>
<dd>
<input 0="Errors" id="emailaddress" name="emailaddress" value="" type="text"></dd>
<dt id="password-label"><label for="password" class="required">Password</label></dt>
<dd>
<input 0="Errors" id="password" name="password" value="" type="password"></dd>
<dt id="captcha-input-label"><label for="captcha-input" class="required">Captcha Code</label></dt>
<dd id="captcha-element">
<img width="200" height="50" alt="" src="/captcha/d7849e6f0b95cad032db35e1a853c8f6.png">
<input type="hidden" name="captcha[id]" value="d7849e6f0b95cad032db35e1a853c8f6" id="captcha-id">
<input type="text" name="captcha[input]" id="captcha-input" value="">
<p class="description">Enter the characters shown into the field.</p></dd>
<dt id="submitButton-label"> </dt><dd id="submitButton-element">
<input id="submitButton" name="submitButton" value="Signup" type="submit"></dd>
<dt id="cancelButton-label"> </dt><dd id="cancelButton-element">
<button name="cancelButton" id="cancelButton" type="button">Cancel</button></dd>
</div></form>
<script type="text/javascript">
$(document).ready(function() {
var widget = dijit.byId("signup");
if (widget) {
widget.destroyRecursive(true);
}
dojo.parser.instantiate([dojo.byId("loginBox")]);
dojo.parser.parse(dojo.byId("loginBox"));
});
</script></div>
any advice on how i can get this to load as a dojo form. by the way i am using Zend_Dojo_Form, if i run the code directly then everything works find but through ajax it doesnt work. thanks.
update
I have discovered that if I load the form in my action and run the __toString() on it it works when i load the form from ajax. It must do preparation in __toString()
Firstly; You need to run the dojo parser on html, for it to accept the data-dojo-type (fka dojoType) attributes, like so:
dojo.parser.parse( dojo.byId("'.$contentNode.'") )
This will of course only instantiate dijits where the dojo type is set to something, for instance (for html5 1.7+ syntax) <form data-dojo-type="dijit.form.Form" action="index.php"> ... <button type="submit" data-dojo-type="dijit.form.Button">Send</button> ... </form>.
So you need to change the ajax contents which is set to innerHTML, so that the parser reckognizes the form of the type dijit.form.Form. That said, I urge people into using a complete set of dijit.form.* Elements as input fields.
In regards to:
$(document).ready(function() {});
This function will never get called. The document, youre adding innerHTML to, was ready perhaps a long time a go.
About Zend in this issue:
Youre most likely rendering the above output form from a Zend_ Dojo type form. If the renderer is set as programmatic, you will see above html a script containing a registry for ID=>dojoType mappings. The behavior when inserting <script> as an innerHTML attribute value, the script is not run under most circumstances (!).
You should try something similar to this pseudo for your form controller:
if request is ajax dojoHelper set layout declarative
else dojoHelper set layout programmatic

Resources