Make jquery plugin work on multiple instances - javascript

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));

Related

JavaScript call function after form submit complete

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.

PHP generated option list only appearing on first Ajax dynamically generated container

I am having an issue where my php generated select/option list is not applying to all of my dynamically generated blocks/containers. It only adds the PHP select to the last container/block instance, despite being called for each container. When troubleshooting with alerts it seems to run through all of the iterations prior to adding the containers/blocks and generating the select, hence why it always appears on the last only-
n = -1
function addDiv() {
n++;
So, a brief overview - on page initialize the code will get how many entries are in the database within a certain criteria and apply that number to 'length', which then runs the function addDiv() that many times. Usually, when adding a block one at a time via button it will populate the created block with a Select/list of Options via php in the addDiv() function, however when automating this with a loop ( the initialize() function ) the above issue occurs.
$( document ).ready(function() {
initialize();
});
function initialize() {
$.ajax({
url: 'get-entries.php',
type: 'POST',
dataType: 'text',
cache: false,
success: function(data) {
result = data;
var arrayJson = JSON.parse(data);
console.log(arrayJson);
length = arrayJson.length;
console.log(length);
for(var i = 0; i < length; i++) {
addDiv();
};
},
error: function(jqXHR) {
alert("Error while fetching data");
console.log("Error while fetching data: " + jqXHR.status + " " + jqXHR.statusText + " " + jqXHR.responseText); //improved error logging
}
});
};
here is the addDiv related code with some redactions to make it easier to read.
var n = -1;
function addDiv() {
n++;
$.post(
"json-option-generator.php",
{}
).done(
function(data)
{
$('#selectedcoin' + n).html(data);
});
$("<div class='coinmarketcap fill' id='container"
+ n +
"'><form id='"
+ n +
"' name='"
+ n +
"' class='formClass' method='post' action=''><select onchange='mySelect(this)' type='text' class='coinname' id='selectedcoin"
+ n +
"' name='selectedcoin"
+ n +
//.etc.....
"' autocomplete='off' value=''><select></select>").appendTo(".main-container");
}
and finally here is the contents of the PHP file for generating the option list based off of json data -
<?php
$json = file_get_contents("../ticker/full.json");
$decode = json_decode($json, true);
sort($decode);
echo '<select name="coinname">';
foreach($decode as $a){
echo "<option value='{$a['id']}'>{$a['name']}</option>";
}
echo '</select>';
?>
I know this is messy and may require a bit of an in depth read through, so I appreciate anyone taking the time to look.
Is there anything glaringly obvious that can help nudge me in the right direction? I have tried breaking the 'addDiv()' calls within initialize() by wrapping 'addDiv()' with a setTimeout function, but no joy.
it should work with this (I named the arguments differently for comprehension, but index and index_t can all be named n):
var n = -1;
function sendToGenerator(index){
var index_t = index;
$.post(
"json-option-generator.php",
{}
).done(
function(data)
{
$('#selectedcoin' + index_t).html(data);
}
);
}
function addDiv() {
n++;
sendToGenerator(n);
$("<div class='coinmarketcap fill' id='container"
+ n +
"'><form id='"
+ n +
"' name='"
+ n +
"' class='formClass' method='post' action=''><select onchange='mySelect(this)' type='text' class='coinname' id='selectedcoin"
+ n +
"' name='selectedcoin"
+ n +
//.etc.....
"' autocomplete='off' value=''><select></select>").appendTo(".main-container");
}

ADD #url.action with parameter on Table cell in AJAX

I am new to this and I want to add a action method on table cell. The problem is Table is generated by java-script(AJAX).
Here's code:
$.ajax({
url: "GetData",
contentType: "application/json; charset=utf-8",
dataType: "json",
type: "POST",
success: function (obj) {
debugger;
$tbl.empty();
$tbl.append('<tr><th>ID</th><th>Name</th><th>Last Executed Date</th><th>Status</th></tr>');
for (var i = 0; i < obj.length; i++) {
$tbl.append(' <tr><td> ' + obj[i].senderId + '</td><td>' + obj[i].subject + '</td><td>' + obj[i].msg + '</td><td>TESTING</td></tr>');
}
}
});
Now instead of <a href="#"> I want to add Action Method #URL.Action on that <td>. Here's my Action Method:
<a href=#Url.Action("SingleSentShow","Home", new { msgId ='+obj[i].senderId+',receiverId='+obj[i].senderId+ })>
But it shows error, I can't use javascript variable obj[i].senderId with c# code #Url.Action("SingleSentShow","Home", new { msgId ='+obj[i].senderId+'...
How can I fix this, or is there any other solution to add link or onClick on Table cell and pass data with it ?
David is right, but a simplified way for easy understanding.
var href = #Url.Action("SingleSentShow","Home", new { msgId ="__msgID__" ,receiverId="__receiverID__" });
href = href.replace("__mgsID__",obj[i].senderId).replace("__receiverID__",obj[i].senderId);
$tbl.append(' <tr><td> <a href="' + href + '">' + '... the rest of your line');
Both will work fine.
Update: As per Comment.
Move the value of href to data-href and set href to # and add a new class for script to work. And when the link is clicked we can swap the values.
$tbl.append(' <tr><td> <a href=# class=Test data-href="' + href + '">' + '... the rest of your line');
And add the below script.
$(document).on('click', '.Test', function () {
$(this).attr('href',$(this).attr('data-href'));
});
You can't mix server-side code and client-side code like that.
One option might be to put the base action URL in a JavaScript variable, and then append your query string parameters to it in JavaScript code. Something like this:
var singleSentShowURL = '#Url.Action("SingleSentShow","Home")';
This would result in something like this client-side:
var singleSentShowURL = '/Home/SingleSentShow';
Then in your loop you could use that variable to manually build the URL. Something like this:
$tbl.append(' <tr><td> <a href="' + singleSentShow + "?msgId=" + obj[i].senderId + "&receiverId=" + obj[i].senderId + '">' + '... the rest of your line');
You might split it into multiple lines for readability:
var href = singleSentShow + "?msgId=" + obj[i].senderId + "&receiverId=" + obj[i].senderId;
$tbl.append(' <tr><td> <a href="' + href + '">' + '... the rest of your line');

adding fields (inputs) to images

im using dropzone to upload multiple images, and works fine, untill i want to insert a brand and url to each image.
The only issue im having is when im going to get the values from the input fields, im getting in myt request from the server undefined values from the fieds (brand, url) but if im using static text it appears no problem.
Here is my code:
$('#add').on('click',function(e){
e.preventDefault();
myDropzone.processQueue();
});
Dropzone.autoDiscover = false;
// Dropzone class:
var myDropzone = new Dropzone("div#myId", {
url: "/galleries",
autoProcessQueue:false,
headers: {
'X-CSRF-TOKEN': 'vjghjghjhgjghjghjghjgLxX',
},
params: {
'brand': $('#brand').val(),
'url' : $('#url').val(),
'description': 'small detail'
},
previewTemplate: "<div class=\"dz-preview dz-file-preview\">\n " +
"<div class=\"dz-image\"><img data-dz-thumbnail /></div>\n " +
"<input type=\"text\" id=\"brand\" name=\"dz-brand\">\n " +
"<input type=\"text\" id=\"url\" name=\"dz-url\">\n
..../div>"
}
);
EDIT: Updated all of this answer:
Your Ids are not unique, therefore you can't reliably get the input data from the ID selector.
Change your IDs on your inputs in the template to classes like this:
previewTemplate: "<div class='dz-preview dz-file-preview'>\n " +
"<div class='dz-image'><img data-dz-thumbnail /></div>\n " +
"<input type='text' class='dz-brand' value='This is the text'> \n " +
"<input type='text' class='dz-url'>\n </div>"
Then add the parameters with the sending event, this will get the input values at the time of upload.
myDropzone.on("sending", function(file, xhr, formData) {
formData.append('brand' , $(file.previewElement).find('.dz-brand').val());
formData.append('url' , $(file.previewElement).find('.dz-url').val());
formData.append('description', 'small detail');
});
Refer to the Documentation here: http://www.dropzonejs.com/#event-sending

Ajax Form Submit not loading newly submitted data

I updated jquery so i could play with the new jquery mobile ui 1.3 and for some reason my form no longer update page any more, it worked previously but it wasn't through ajax, it simply submitted the form without ajax, I would however like ajax to just fetch the new data and append it to the div instead of reloading the whole page again when the popup closes.
I use a popup module for the form and on submission it should append the new information to #content ul
The JS.
<!-- Load Json data and events -->
<script type="text/javascript">
jQuery('#new_rave').live('submit',function( event ) {
$.ajax({
url: 'http://whoops/goodtimes',
type: 'POST',
dataType: 'json',
data: $('#new_rave').serialize(),
success: function( data ) {
for( var id in data ) {
jQuery('#').html(data[id]);
}
}
});
return false;
});
$(document).ready(function() {
$.getJSON('http://whoops/goodtimes', function( goodtimes ) {
$.each(goodtimes, function( goodtime ) {
var output =
"<li><a href="+this.goodtime.id+">" +
"<h3>" + this.goodtime.title + "</h3>" +
"<p>" + this.goodtime.post + "</p>" +
"<p class='ui-li-aside'><strong>" +
this.goodtime.created_at + "</strong></p>" +
"</a></li>";
$('#content ul').append(output).listview('refresh');
});
});
});
</script>
The form
<!-- New item Popup -->
<div data-role="popup" class="ui-content"
data-overlay-theme="a" data-position-to="window" id="add">
<form id="new_rave">
<label for="goodtime_title">Title</label>
<input type="text" name="goodtime[title]" id="goodtime_title">
<label for="goodtime_post">Rave</label>
<div data-role="fieldcontain">
<textarea name="goodtime[post]" id="goodtime_post"></textarea>
</div>
<input type="submit" value="submit">
</form>
</div>
and the content div
<div id="content" data-role="content">
<ul data-role="listview" data-theme="d" data-divider-theme="d"></ul>
</div><!-- /content -->
Intro
Your problem is probably due to $(document).ready(function(){. In jQuery Mobile, Ajax is used to load the content of each page into the DOM as you navigate. Because of this $(document).ready() will trigger before your first page is loaded and every code intended for page manipulation will be executed after a page refresh.
Everything here can be found described with more details in my personal blog article.
In case this is not a problem, use Firefox/Chrome plugin Firebug to test if ajax call has reached a server and if response has been received.
Last thing, don't refresh listview every time you append a new element. listview refresh is a huge time sink, every refresh can last around 50ms but do it numerous time and your restyling could go forever.
Solution
So change this:
$.getJSON('http://whoops/goodtimes', function(goodtimes) {
$.each(goodtimes, function(goodtime) {
var output =
"<li><a href="+this.goodtime.id+">" +
"<h3>" + this.goodtime.title + "</h3>" +
"<p>" + this.goodtime.post + "</p>" +
"<p class='ui-li-aside'><strong>" + this.goodtime.created_at + "</strong></p>" +
"</a></li>";
$('#content ul').append(output).listview('refresh');
});
});
to this:
$.getJSON('http://whoops/goodtimes', function(goodtimes) {
$.each(goodtimes, function(goodtime) {
var output =
"<li><a href="+this.goodtime.id+">" +
"<h3>" + this.goodtime.title + "</h3>" +
"<p>" + this.goodtime.post + "</p>" +
"<p class='ui-li-aside'><strong>" + this.goodtime.created_at + "</strong></p>" +
"</a></li>";
$('#content ul').append(output);
});
$('#content ul').listview('refresh');
});
EDIT
Your problem with constant post repeating comes to how jQuery Mobile handles event binding. Because pages are constantly revisited each time events are going to be bound over and over. In your case that would be an event that executes JSON call.
This can be prevented in several ways, most common one is to unbind event before binding it. For example:
$('#test-button').off('click').on('click', function(e) {
alert('Button click');
});

Categories

Resources