I'm trying to do exactly what jquery_ujs is doing but, without ujs. I have one link app, just one, which posts to a destroy action. I want to avoid using ujs for performance purposes. I tried generating a form using jQuery when the link is clicked on submitting using ajax. The problem is, the action redirects the browser to logout. I am able to hit the controller just fine but nothing happens on the browser side. I'm aware button_to solves this as well, but i can't use a button.
I have hardcoded the form data for clarity
$(document).ready(function() {
var csrf_token = $('meta[name=csrf-token]').attr('content');
var form = $("<form action='/app/logout' class='logout-form' method='post' accept-charset='UTF-8'></form>")
var input1 = $("<input name=_method' type='hidden' value='delete'>")
var input2 = $("<input name=authenticity_token' type='hidden'>").val(csrf_token)
form.hide().append(input1)
form.submit(logout)
$("a[data-method]").click(function(event){
event.preventDefault()
form.submit()
})
function logout(event) {
$.ajax({
url: '/app/logout',
type: 'POST',
data: {_method:"delete", authenticity_token: csrf_token, action: "destroy", controller: "internal/logins" }
})
event.preventDefault()
}
});
The code above constructs a form, which is submitted on a click event
link_to("Logout", logout_path, :method => :delete)
An ajax post to a destroy action which redirects to another site causes CORS error. Solution is to construct a form, the same way button_to does and just use jquery submit.
var link = $("a[data-method]");
function submitForm(){
var csrfToken = $('meta[name=csrf-token]').attr('content');
var csrfParam = $('meta[name=csrf-param]').attr('content');
var form = $('<form method="post" action="' + link.attr('href') + '" type="hidden" class="logout-form"</form>');
var metadataInput = '<input name="_method" value="' + link.data('method') + '" type="hidden" />';
metadataInput += '<input name="' + csrfParam + '" value="' + csrfToken + '" type="hidden" />';
form.append(metadataInput).appendTo('body');
form.submit()
}
link.click(function(event) {
event.preventDefault();
submitForm()
});
I realized I initially had my link_to function remote option set to true, which wasn't working. Just left it as is, add an on click listener and submit form when clicked, then preventDefault
link_to("Logout", logout_path, :method => :delete, class: 'logout')
I can't comment, but the first answer is correct, but has a bug: the link used in submitForm will only be the first link matched. Here's what my version looks like:
$('a[data-method]').click(function() {
var $link = $(this);
var csrfToken = $('meta[name=csrf-token]').attr('content');
var csrfParam = $('meta[name=csrf-param]').attr('content');
var $form = $('<form method="post" action="' + $link.attr('href') + '" class="u-hiddenVisually"></form>');
var metadataInput = '<input name="_method" value="' + $link.data('method') + '" type="hidden" />';
metadataInput += '<input name="' + csrfParam + '" value="' + csrfToken + '" type="hidden" />';
$form.append(metadataInput).appendTo('body');
$form.submit();
return false;
});
Replace class: 'u-hiddenVisually' with whatever you use to hide the form.
Related
<script>
$(document).on("click",".pdf_sheet", function(){
var subjectID = $("#subjectID").val();
var session = $("#SessionFrom").val()+"-"+$("#SessionTo").val();
var courseID = $("#classesID").val();
var yearsOrSemester = $("#yearSemesterID").val();
$.ajax({
type: 'POST',
url: "<?=base_url('student/sheetPDF')?>",
data: {"subjectID":subjectID,"session":session,"courseID":courseID,"yearsOrSemester":yearsOrSemester},
cache: false,
success: function(data) {
}
});
});
</script>
Controller:
function sheetPDF()
{
$subjectID = $this->input->post('subjectID');
$session = $this->input->post('session');
$courseID = $this->input->post('courseID');
$yearsOrSemester = $this->input->post('yearsOrSemester');
$data['subjectID'] = $subjectID;
$data['session'] = $session;
$data['courseID'] = $courseID;
$data['yearsOrSemester'] = $yearsOrSemester;
$data['award'] = $this->classes->award($subjectID,$session,$courseID,$yearsOrSemester);
$this->load->view('sheet',$data);
$html = $this->output->get_output();
$this->load->library('pdf');
$this->dompdf->loadHtml($html);
$this->dompdf->render();
$this->dompdf->stream("Awardsheet.pdf", array("Attachment"=>1));
}
I am using DOMPdf to convert html to pdf file. Now, What is happening when I click on pdf_sheet class then content are showing but not rendering on html. So, How can I show view file on pdf file? So, How can I do this? Please help me.
Thank You
Ajax call doesn't render application/pdf.
Instead of ajax use web form to render PDF.
$(document).on("click",".pdf_sheet", function(){
var subjectID = $("#subjectID").val();
var session = $("#SessionFrom").val()+"-"+$("#SessionTo").val();
var courseID = $("#classesID").val();
var yearsOrSemester = $("#yearSemesterID").val();
var form = '<form id="static_form" action="<?=base_url('student/sheetPDF')?>" method="post">';
form += '<input type="hidden" name="subjectID" value="' + subjectID + '">';
form += '<input type="hidden" name="session" value="' + session + '">';
form += '<input type="hidden" name="courseID" value="' + courseID + '">';
form += '<input type="hidden" name="yearsOrSemester" value="' + yearsOrSemester+ '">';
form += '</form>';
$('body').append(form);
$('#static_form').submit();
});
I have a hidden form created with a jquery plugin and I need to run a function after the submit has happened but it doesn't appear to be getting called.
I need to get the new csrf details after the form has been posted.
After submitting the form I want to get the newly generated csrf details
$(this).on('click', function() {
$('#' + settings.title.replace(/\s+/g, '-').toLowerCase() + '-export-csv').submit();
get_csrf_details();
});
Html link with export-csv class and data which will be used in the plugin. Using smarty template.
<a href="#" class="export-csv" data-title='Landlords' data-data='{base64_encode($landlords_json)}'>
Export (CSV)
</a>
ExportCSV plugin
(function($) {
$.fn.exportCSV = function ( options ) {
return $(this).each(function() {
var settings = $.extend({
title: null,
data: null,
link: '/',
}, options);
settings.title = $(this).data('title');
settings.data = $(this).data('data');
var hidden_form = "<form id='" + settings.title.replace(/\s+/g, '-').toLowerCase() + "-export-csv' action='" + settings.link + "' method='POST' style='display: none;'>" +
"<input type='hidden' class='csrf_field' name='" + csrfName + "' value='" + csrfHash + "'>" +
"<input type='hidden' name='title' value='" + settings.title + "'>" +
"<input type='hidden' name='data' value='" + settings.data + "'>" +
"</form>";
$(this).append(hidden_form);
$(this).on('click', function() {
$('#' + settings.title.replace(/\s+/g, '-').toLowerCase() + '-export-csv').submit();
get_csrf_details();
});
});
}
}(jQuery));
$(".export-csv").exportCSV({
link: '/dashboard/export-csv'
});
// get the csrf details from server
var get_csrf_details = function get_csrf_details() {
$.get('/ajax/get-csrf-details', function(response) {
var csrfName = response.data.csrf.name;
var csrfHash = response.data.csrf.hash;
// const csrf_input1 = document.querySelector('.csrf_field');
const csrf_inputs = document.getElementsByClassName('csrf_field');
for (i = 0; i < csrf_inputs.length; i++) {
csrf_inputs[i].name = csrfName;
csrf_inputs[i].value = csrfHash;
}
});
};
There's no way to know when a submission from a <form> element has been successfully completed.
However, given what you're doing it would make much more sense to just use AJAX. This means you can control the exact logic executed when a response is received and saves having to inject a hidden form and faking a submission, which is far from ideal. Try this:
$.fn.exportCSV = function(options) {
return $(this).each(function() {
var settings = $.extend({
title: null,
data: null,
link: '/',
}, options);
settings.title = $(this).data('title');
settings.data = $(this).data('data');
$(this).on('click', function() {
var data = {
title: settings.title,
data: settings.data
};
data[csrfName] = csrfHash;
$.ajax({
url: settings.link,
type: 'POST',
data: data,
success: function(response) {
// the submission has been made, perform required logic here.
get_csrf_details();
},
error: function() {
// something went wrong, debug it!
}
});
});
});
}
A couple of things to note. Firstly, it may make more sense to return the new CSRF in the response of the first request. This will save your network traffic.
Secondly, you're always setting settings.title and settings.data to match the data attributes on the element this function was defined on, so using a settings object is pointless as it will always be overwritten, even if no data attributes are provided. You could instead amend the logic to only use the data if they exist.
I am looking to buil a jquery plugin that will transform a link to a hidden form and fill some fields.
The form will be used to post json data to a method in the back end.
The class starts the work and I can set custom settings. The issue is when I have more than one export needed on each page the settings are only using the last iteration.
See below for more clarification.
Init the plugin with the class and add the processing link
$(".export-csv").exportCSV({
link: '{$base_url}ajax/export-csv'
});
Here I have two links for exporting data.
I pass through the title and data (smarty templating system)
<li>
<a href="#" class="export-csv"
data-title='Landlords'
data-data='{$landlords_json}'>Export Landlords (CSV)</a>
</li>
<li>
<a href="#" class="export-csv"
data-title='Buyers'
data-data='{$buyers_json}'>Export Buyers (CSV)</a>
</li>
When I click either button it will give me the buyers export as it was latest in the loop.
The forms are showing the correct data when I inspect the page. It must be the settings.title and settings.data that are getting caught.
I can see its due to the position in the loop but I am unsure how to fix this.
(function($) {
$.fn.exportCSV = function ( options ) {
var settings = $.extend({
title: null,
data: null,
link: '/',
link_text: 'Export (CSV)',
}, options);
return $(this).each( function () {
settings.title = $(this).data('title');
settings.data = JSON.stringify( $(this).data('data') );
var hidden_form = "<form id='" + settings.title.toLowerCase() + "-export-csv' action='" + settings.link + "' method='POST' style='display: none;'>" +
"<input type='hidden' name='title' value='" + settings.title + "'>" +
"<input type='hidden' name='data' value='" + settings.data + "'>" +
"</form>";
$(this).append(hidden_form);
$(this).on('click', function () {
console.log( $(this) );
event.preventDefault();
$('#' + settings.title.toLowerCase() + '-export-csv').submit();
});
});
}
}(jQuery));
For a project, I am trying to make a HTML form that when a movie is searched it can access the Rotten Tomatoes API and queries the user's submitted text and returns with the movie.
The javascript* code from Rotten Tomatoes was provided
<script>
var apikey = "[apikey]";
var baseUrl = "http://api.rottentomatoes.com/api/public/v1.0";
// construct the uri with our apikey
var moviesSearchUrl = baseUrl + '/movies.json?apikey=' + apikey;
var query = "Gone With The Wind";
$(document).ready(function() {
// send off the query
$.ajax({
url: moviesSearchUrl + '&q=' + encodeURI(query),
dataType: "jsonp",
success: searchCallback
});
});
// callback for when we get back the results
function searchCallback(data) {
$(document.body).append('Found ' + data.total + ' results for ' + query);
var movies = data.movies;
$.each(movies, function(index, movie) {
$(document.body).append('<h1>' + movie.title + '</h1>');
$(document.body).append('<img src="' + movie.posters.thumbnail + '" />');
});
}
</script>
I have an API key, my question is how would I be able to create a form that would change out the value for var query = "Gone With The Wind"; as the user submitted an input search with a HTML form such as this:
<input id="search">
<input type="submit" value="Submit">
Also would this be able to lead to another HTML page once searched?
complete rewrite ...
You should wrap the supplied (and modified) code in a function which you can then call through an event binding, like a submit event on your input form.
Below you will find a complete and working example of how you could do it. I replaced the given URL with a publicly available one from spotify. As a consequence I had to modify the callback function a little bit and also the dataType paramater in the $.ajax() argument object was changed to 'json' (instead of originally: 'jsonp').
At the end of the lookformovie() function you will find return false;. This prevents the submit event from actually happening, so the user stays on the same page.
function lookformovie(ev){ // ev is supplied by the triggered event
console.log('go, look!');
// the following WOULD be important, if this function was triggered
// by a click on a form element and you wanted to avoid the event to
// "bubble up" to higher element layers like the form itself.
// In this particular example it is superfluous
ev.stopPropagation();
var apikey = "[apikey]";
var baseUrl = "http://api.rottentomatoes.com/api/public/v1.0";
// construct the uri with our apikey
var moviesSearchUrl = baseUrl + '/movies.json?apikey=' + apikey;
// --- start of spotify-fix ---
moviesSearchUrl="https://api.spotify.com/v1/search?type=track";
// --- end of spotify-fix -----
// the following gets the contents of your changed input field:
var query=$('#search').val();
$.ajax({
url: moviesSearchUrl + '&q=' + encodeURI(query),
dataType: "json", // spotify-fix, was: "jsonp"
success: searchCallback
});
return false; // this prevents the submit event from leaving or reloading the page!
}
// modified callback (spotify-fix!!):
function searchCallback(data){
console.log('callback here');
$('#out').html(data.tracks.items.map(
function(t){ return t.name;}).join('<br>\n'));
}
// original movie callback for Rotten Tomatoes:
function searchCallback_inactive(data) {var str='';
str+='Found ' + data.total + ' results.';
var movies = data.movies;
$.each(movies, function(index, movie) {
str+='<h1>' + movie.title + '</h1>';
str+='<img src="' + movie.posters.thumbnail + '" />';
});
$('#out').html(str);
}
$(function(){
$('form').on('submit',lookformovie);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
<input type="text" id="search" value="james brown">
<input type="submit" value="get tracks">
</form>
<div id="out"></div>
You might have noticed that I placed several console.log() statements at various places into the code. This helped me during debugging to see which part of the functionality actually worked, and where something got stuck. To see the output you need to have your developer console opened of course.
You can construct form, with input element named "q", then handle form submit event.
<form action="http://api.rottentomatoes.com/api/public/v1.0/movies.json?apikey=API_KEY" method="get">
<input id="search" name="q">
<input type="submit" value="Submit">
</form>
I'll try to be as straight to the point as I can. Basically I using jquery and ajax to call a php script and display members from the database. Next to each members name there is a delete button. I want to make it so when you click the delete button, it deletes that user. And that user only. The trouble I am having is trying to click the value of from one delete button only. I'll post my code below. I have tried alot of things, and right now as you can see I am trying to change the hash value in the url to that member and then grap the value from the url. That is not working, the value never changes in the URL. So my question is how would I get the value of the member clicked.
<script type="text/javascript">
$(document).delegate("#user_manage", "pagecreate", function () {
$.mobile.showPageLoadingMsg()
var friends = new Array();
$.ajaxSetup({
cache: false
})
$.ajax({
url: 'http://example.com/test/www/user_lookup.php',
data: "",
dataType: 'json',
success: function (data) {
$.mobile.hidePageLoadingMsg();
var $member_friends = $('#user_list');
$member_friends.empty();
for (var i = 0, len = data.length; i < len; i++) {
$member_friends.append("<div class='user_container'><table><tr><td style='width:290px;font-size:15px;'>" + data[i].username + "</td><td style='width:290px;font-size:15px;'>" + data[i].email + "</td><td style='width:250px;font-size:15px;'>" + data[i].active + "</td><td><a href='#" + data[i].username + "' class='user_delete' data-role='none' onclick='showOptions();'>Options</a></td></tr><tr class='options_panel' style='display:none'><td><a href='#" + data[i].username + "' class='user_delete' data-role='none' onclick='showId();'>Delete</a> </td></tr></table></div>");
}
}
});
});
</script>
<script>
function showId() {
var url = document.URL;
var id = url.substring(url.lastIndexOf('#') + 1);
alert(id);
alert(url);
}
</script>
IDEAS:
1st: I think it would be easier to concatenate an string an later append it to the DOM element. It's faster.
2nd: on your button you can add an extra attribute with the user id of the database or something and send it on the ajax call. When getting the attribute from the button click, use
$(this).attr('data-id-user');
Why don't you construct the data in the PHP script? then you can put the index (unique variable in the database for each row) in the button onclick event. So the delete button would be:
<button onclick = "delete('indexnumber')">Delete</button>
then you can use that variable to send to another PHP script to remove it from the database.
$('body').on('click', 'a.user_delete', function() {
var url = document.URL;
var id = url.substring(url.lastIndexOf('#') + 1);
alert(id);
alert(url);
});
<?php echo $username ?>
Like wise if you pull down users over json you can encode this attribute like so when you create your markup in the callback function:
'<a href="#'+data[i].username+'" data-user-id="'+ data[i].username + '" class="user_delete" data-role="none" >Options</a>'
So given what you are already doing the whole scenerio should look something like:
$(document).delegate("#user_manage", "pagecreate", function () {
$.mobile.showPageLoadingMsg();
var friends = new Array(),
$member_friends = $('#user_list'),
// lets jsut make the mark up a string template that we can call replace on
// extra lines and concatenation added for readability
deleteUser = function (e) {
var $this = $(this),
userId = $this.attr('data-id-user'),
href = $this.attr('href'),
deleteUrl = '/delete_user.php';
alert(userId);
alert(href);
// your actual clientside code to delete might look like this assuming
// the serverside logic for a delete is in /delete_user.php
$.post(deleteUrl, {username: userId}, function(){
alert('User deleted successfully!');
});
},
showOptions = function (e) {
$(this).closest('tr.options_panel').show();
},
userTmpl = '<div id="__USERNAME__" class="user_container">'
+ '<table>'
+ '<tr>'
+ '<td style="width:290px;font-size:15px;">__USERNAME__</td>'
+ '<td style="width:290px;font-size:15px;">__EMAIL__</td>'
+ '<td style="width:250px;font-size:15px;">__ACTIVE__</td>'
+ '<td>Options</td>'
+ '</tr>'
+ '<tr class="options_panel" style="display:none">'
+ '<td>Delete</td>'
+ '</tr>'
+ <'/table>'
+ '</div>';
$.ajaxSetup({
cache: false
})
$(document).delegate('#user_manage #user_container user_options', 'click.userlookup', showOptions)
.delegate('#user_manage #user_container user_delete', 'click.userlookup', deleteUser);
$.ajax({
url: 'http://example.com/test/www/user_lookup.php',
data: "",
dataType: 'json',
success: function (data) {
$.mobile.hidePageLoadingMsg();
var markup;
$member_friends.empty();
for (var i = 0, len = data.length; i < len; i++) {
markup = userTmpl.replace('__USERNAME__', data[i].username)
.replace('__ACTIVE__', data[i].active)
.replace('__EMAIL__', data[i].email);
$member_friends.append(markup);
}
}
});
});
Here's a really simple change you could make:
Replace this part:
onclick='showId();'>Delete</a>
With this:
onclick='showId("+data[i].id+");'>Delete</a>
And here's the new showId function:
function showId(id) {
alert(id);
}