Trying to create reusable custom ajax form plugin - javascript

Updated code - working
(function($) {
$.fn.mbajaxform = function( mbopts ) {
var mb_form_items = $(this).find('input, submit, button'),
mb_form_type = mb_mbtheme_js[0],
mb_get_page_slug = mb_mbtheme_js[1],
mb_redirect = mb_mbtheme_js[2],
mb_redirect_time = mb_mbtheme_js[3],
mb_form_disable = mb_mbtheme_js[4];
// create the defaults
let mbdefaults = {
beforeSend: function( el, beforeSend ) {
},
success: function( el, success ) {
},
complete: function( el, complete ) {
},
error: function( el, error ) {
}
};
// extend the defaults
let mboptions = $.extend( {}, mbdefaults, mbopts );
return this.each( function() {
// the variable for this
var $this = $(this);
function beforesend_callback(e) {
mboptions.beforeSend( $this, e );
}
function success_callback(e) {
mboptions.success( $this, e );
}
function complete_callback(e) {
mboptions.complete( $this, e );
}
function error_callback(e) {
mboptions.error( $this, e );
}
// run the function
$this.on( mb_form_type, function(mb) {
// stop the default function of buttons
mb.preventDefault();
var mb_ajax_form_data = new FormData( $this[0] );
// do the ajax
$.ajax({
method: "POST",
data: mb_ajax_form_data,
contentType: false,
processData: false,
beforeSend: beforesend_callback,
success: success_callback,
complete: complete_callback,
error: error_callback
});
});
});
};
}( jQuery ));
$("#mbform").mbajaxform();
Original question
This is my first attempt at creating a plugin but was following a few tutorials hoping it would work first go - rookie!
I have an AJAX form that I noticed was being repeated (such as password resets, theme settings, user creation) across a few sub-sites within my network (using Wordpress Multisite), so I decided it could be more beneficial to create a function that was able to be extended (if changes needed) but otherwise apply the defaults.
see edit revisions for older code

At a glance looks like you might not be referencing the correct options variable.
You're setting it with the name mboptions
let mboptions = $.extend({}, mbdefaults, mbopts);
but then trying to access it using options
options.beforeSend($this, e);
And when you're trying to bind the submit event you're not accessing the event name from the options object. So instead of
$this[mb_form_type](function(mb) {...});
I think
$this.on(mboptions.mb_form_type, function(mb) {...}):
is a bit more readable (also you can later remove the binding with this.off(mboptions.mb_form_type) if you need to ;)

Related

how to display multiple modals as you click a button in each consecutive modal

i'm trying to ajax multiple dialogs onto the page and then display the first and subsequent dialogs when the user clicks on the okay button within each dialog. i've got pretty close but it doesn't quite work. The problem i have is that i'm not sure how to close the clicked modal and then display the next modal in sequence. any help much appreciated!???
thanks,
mark up
<div class="mymodal" style="display: none">
<!-- inject modal content into here -->
</div>
javascript code
(function(ns) {
var modalArray = [];
ns.calculateWhatModalsWeNeed = function () {
$.ajax({
url: serviceUrl,
cache: 'testurl',
data: myData,
type: 'post',
success: function (data) {
// based on the response an array is built up
// i.e.
modalArray.push('modal1');
modalArray.push('modal2');
ns.loadModals(modalArray, ns.showModal());
},
dataType: 'json',
contentType: "application/json; charset=utf-8"
});
};
ns.loadModals = function(modalsToShow, callback) {
// call and load the modal mark up into the DOM
for (var i = 0; i < modalsToShow.length; i++) {
var successCallBack = function (html) {
$('.mymodal').append(html);
};
// Load modal window onto page
var modalUrl = 'myurl' + modalsToShow[i];
// ajax command to call the mvc controller
// the modalsToShow array are the view names
// i.e. 'myurl' + '/' + modalsToShow[i];
ajaxcommand.get(...);
}
if (callback && typeof (callback) === 'function') callback();
};
ns.showModal = function () {
// this is the problem i think - how to
// trigger each modal here as you click okay on each one..?
$('mymodal:first').dialog({
width: 633,
closeOnEscape: true,
modal: true
});
};
})(namespace('stackoverflow.problem'));
You will want to use the close event for the dialog.
$('mymodal:first').dialog({
width: 633,
closeOnEscape: true,
modal: true,
close: function(event, ui) {
// do something...
}
});
You can also bind event listener like so:
$( ".selector" ).on( "dialogclose", function( event, ui ) {} );
On a side note, you are missing a . before your mymodal class.

jQuery use variable outside function

I'm using jquery.feeds.js to aggregate rss feeds and preprocessing the data received with jsonp.js. The problem is I can't use the variable summarize I've set within the preprocess function outside of it. I did set it as a universal variable though so I don't know what I could be doing wrong. Could it be a problem that I'm running multiple JSON requests?
My code:
$('#feed').feeds({
feeds: {
reuters: 'http://feeds.reuters.com/reuters/businessNews'
},
max: 2,
preprocess: function ( feed ) {
var articleLink = (this.link);
var summarize = '';
$.getJSON({
url: 'https://jsonp.nodejitsu.com/?url=http://clipped.me/algorithm/clippedapi.php?url='+articleLink+'&callback=?',
corsSupport: true,
jsonpSupport: true,
success: function(data){
var summarize = data.summary
}
});
alert(summarize);
this.contentSnippet = summarize
},
entryTemplate: '<h3><!=title!></h3><p><!=contentSnippet!></p><i><!=link!></i>'
});
And a JSFIDDLE
You have a series of errors that are not addressed in the other posts..
the preprocess callback allows for changes in the current object (feed) right before it gets displayed.
Since the getJSON is an ajax call it will get the results too late. And changing the contentSnippet even in the success callback will not fix this.
You use the $.getJSON method as if it was $.ajax. So you pass it wrong arguments. Just use $.ajax for your syntax
finally to fix the first issue, you need to alter your template a bit so you can find the relevant parts later on (when the ajax requests complete) and use the onComplete callback instead (of the feeds plugin)
All changes together give
$('#feed').feeds({
feeds: {
reuters: 'http://feeds.reuters.com/reuters/businessNews'
},
max: 2,
onComplete: function(entries){ // use onComplete which runs after the normal feed is displayed
var $this = $(this);
entries.forEach(function(entry){
var $self = $this.find('.entry[data-link="'+entry.link+'"]');
$.ajax({
url:'https://jsonp.nodejitsu.com/?url=http://clipped.me/algorithm/clippedapi.php?url='+entry.link,
corsSupport: true,
jsonpSupport: true,
success: function(data){
// add the results to the rendered page
$self.find('.snippet').html( data.summary );
}
});
});
}, // change the template for easier access through jquery
entryTemplate: '<div class="entry" data-link="<!=link!>"><h3><!=title!></h3><p class="snippet"><!=contentSnippet!></p><i><!=link!></i></div>'
});
Demo at http://jsfiddle.net/gaby/pc7s2bmr/1/
I think you mean this
$('#feed').feeds({
feeds: {
reuters: 'http://feeds.reuters.com/reuters/businessNews'
},
max: 2,
preprocess: function ( feed ) {
var articleLink = (this.link);
var summarize = '';
var that = this;
$.getJSON({
url: 'https://jsonp.nodejitsu.com/?url=http://clipped.me/algorithm/clippedapi.php?url='+articleLink+'&callback=?',
corsSupport: true,
jsonpSupport: true,
success: function(data){
that.contentSnippet = data.summary
}
});
},
entryTemplate: '<h3><!=title!></h3><p><!=contentSnippet!></p><i><!=link!></i>'
});
Mathletics is correct. Do this...
$('#feed').feeds({
feeds: {
reuters: 'http://feeds.reuters.com/reuters/businessNews'
},
max: 2,
preprocess: function ( feed ) {
var articleLink = (this.link);
var summarize = '';
var _this = this;
$.getJSON({
url: 'https://jsonp.nodejitsu.com/?url=http://clipped.me/algorithm/clippedapi.php?url='+articleLink+'&callback=?',
corsSupport: true,
jsonpSupport: true,
success: function(data){
_this.contentSnippet = data.summary
}
});
alert(summarize);
},
entryTemplate: '<h3><!=title!></h3><p><!=contentSnippet!></p><i><!=link!></i>'
});

Pub/Sub scope in jQuery

I am attempting to implement a Pub/Sub pattern in jQuery with the following code :
$.each({
trigger : 'publish',
on : 'subscribe',
off : 'unsubscribe'
}, function ( key, val) {
jQuery[val] = function() {
o[key].apply( o, arguments );
};
});
This works fine until I attempt to build something with multiple instances.
I have an activity object that is applied to each $('.activity_radio') div element. When I click on a radio button inside any $('.activity_radio') div the $.subscribe event will trigger (X) amount of times based on the number of activity_radio divs on are on the page.
How do I publish/subscribe events based only within a particular div?
Code
Radio Activity ( radio-activity.js )
var activity = {
init : function ( element ) {
// get our boilerplate code
this.activity = new util.factories.activity();
this.element = element;
this.$element = $(element);
// other init code
// gather our radio elements
this.target_element = this.$elem.find('input[type=radio]');
// send our radio elements to onSelect
this.activity.onSelect(this.target_element);
// trigger click function that will subscribe us to onSelect publish events
this.click()
},
// subscribe to events
click : function()
{
$.subscribe('activity.input.select', function ( event, data ){
// we have access to the value the user has clicked
console.log(data);
// trigger another function // do something else
});
}
}
Base Activity Boilerplate Code ( activity-factory.js )
var activity_factory = factory.extend({
init: function(e)
{
// init code
},
onSelect : function ( inputs ) {
inputs.on('click', function(){
// do some processing
// retrieve the value
var data = $(this).val();
// announce that the event has occured;
$.publish( 'activity.input.select', data );
});
}
}
});
Triggered when DOM is ready
$(function(){
// foreach DOM element with the class of activity_radio
$('.activity_radio').each(function(){
// trigger the init func in activity object
activity.init(this);
});
});
You can write your subscribe/publish as a plugins
$.each({
trigger : 'publish',
on : 'subscribe',
off : 'unsubscribe'
}, function ( key, val) {
jQuery.fn[val] = function() {
this[key].apply(this, Array.prototype.slice.call(arguments));
};
});
And you will be able to call it on $element
this.$element.subscribe('activity.input.select', function(event, data) {
and
onSelect: function ( inputs ) {
var self = this;
inputs.on('click', function(){
// do some processing
// retrieve the value
var data = $(this).val();
// announce that the event has occured;
self.$element.publish('activity.input.select', data);
});
}

How to show processing animation / spinner during ajax request?

I want a basic spinner or processing animation while my AJAX POST is processing. I'm using JQuery and Python. I looked at the documentation but can't figure out exactly where to put the ajaxStart and ajaxStop functions.
Here is my js:
<script type="text/javascript">
$(function() {
$('.error').hide();
$("#checkin-button").click(function() {
var mid = $("input#mid").val();
var message = $("textarea#message").val();
var facebook = $('input#facebook').is(':checked');
var name = $("input#name").val();
var bgg_id = $("input#bgg-id").val();
var thumbnail = $("input#thumbnail").val();
var dataString = 'mid='+mid+'&message='+message+'&facebook='+facebook+'&name='+name+'&bgg_id='+bgg_id+'&thumbnail='+thumbnail;
$.ajax({
type: "POST",
url: "/game-checkin",
data: dataString,
success: function(badges) {
$('#checkin-form').html("<div id='message'></div><div id='badges'></div>");
$('#message').html("<h2><img class=\"check-mark\" src=\"/static/images/check-mark.png\"/>You are checked in!</h2>");
$.each(badges, function(i,badge) {
$('#badges').append("<h2>New Badge!</h2><p><img class='badge' src='"+badge.image_url+"'><span class='badge-title'>"+badge.name+"</span></p>");
});
}
});
return false;
});
});
</script>
$.ajax({
type: "POST",
url: "/game-checkin",
data: dataString,
beforeSend: function () {
// ... your initialization code here (so show loader) ...
},
complete: function () {
// ... your finalization code here (hide loader) ...
},
success: function (badges) {
$('#checkin-form').html("<div id='message'></div><div id='badges'></div>");
$('#message').html("<h2><img class=\"check-mark\" src=\"/static/images/check-mark.png\"/>You are checked in!</h2>");
$.each(badges, function (i, badge) {
$('#badges').append("<h2>New Badge!</h2><p><img class='badge' src='" + badge.image_url + "'><span class='badge-title'>" + badge.name + "</span></p>");
})
}
});
http://api.jquery.com/jQuery.ajax/:
Here are the callback hooks provided by $.ajax():
beforeSend callback is invoked; it receives the jqXHR object and the settings map as parameters.
error callbacks are invoked, in the order they are registered, if the request fails. They receive the jqXHR, a string indicating the error type, and an exception object if applicable. Some built-in errors will provide a string as the exception object: "abort", "timeout", "No Transport".
dataFilter callback is invoked immediately upon successful receipt of response data. It receives the returned data and the value of dataType, and must return the (possibly altered) data to pass on to success.
success callbacks are then invoked, in the order they are registered, if the request succeeds. They receive the returned data, a string containing the success code, and the jqXHR object.
complete callbacks fire, in the order they are registered, when the request finishes, whether in failure or success. They receive the jqXHR object, as well as a string containing the success or error code.
Note the beforeSend and complete method additions to the code.
Hope that helps.
If you're using jQuery 1.5 you could do that nicely, unobtrusively and generically with a prefilter. Let's make a very simple plugin for this:
(function($) {
var animations = {};
$.ajaxPrefilter(function( options, _, jqXHR ) {
var animation = options.animation && animations[ options.animation ];
if ( animation ) {
animation.start();
jqXHR.then( animation.stop, animation.stop );
}
});
$.ajaxAnimation = function( name, object ) {
if ( object ) {
animations[ name ] = object;
}
return animations[ name ];
};
})( jQuery );
You install an animation as follows:
jQuery.ajaxAnimation( "spinner" , {
start: function() {
// code that starts the animation
}
stop: function() {
// code that stops the animation
}
} );
then, you specify the animation in your ajax options:
jQuery.ajax({
type: "POST",
url: "/game-checkin",
data: dataString,
animation: "spinner",
success: function() {
// your success code here
}
});
and the prefilter will ensure the "spinner" animation is started and stopped when needed.
Of course, that way, you can have alternative animations installed and select the one you need per request. You can even set a default animation for all requests using ajaxSetup:
jQuery.ajaxSetup({
animation: "spinner"
});
The best method I have found, assuming you are populating a present but empty field is to have a .loading class defined with background-image: url('images/loading.gif') in your CSS. You can then add and remove the loading class as necessary with jQuery.
you can set global ajax loading icon handler using here #ajxLoader takes your loading icon
$( document ).ajaxStart(function() {
$("#ajxLoader").fadeIn();
});
$( document ).ajaxComplete(function() {
$("#ajxLoader").fadeOut();
});
$(function() {
$('.error').hide();
$("#checkin-button").click(function() {
var mid = $("input#mid").val();
var message = $("textarea#message").val();
var facebook = $('input#facebook').is(':checked');
var name = $("input#name").val();
var bgg_id = $("input#bgg-id").val();
var thumbnail = $("input#thumbnail").val();
var dataString = 'mid=' + mid + '&message=' + message + '&facebook=' + facebook + '&name=' + name + '&bgg_id=' + bgg_id + '&thumbnail=' + thumbnail;
$.ajax({
type : "POST",
url : "/game-checkin",
data : dataString,
beforeSend : function() {
$('#preloader').addClass('active');
},
success : function(badges) {
$('#preloader').removeClass('active');
$('#checkin-form').html("<div id='message'></div><div id='badges'></div>");
$('#message').html("<h2><img class=\"check-mark\" src=\"/static/images/check-mark.png\"/>You are checked in!</h2>");
$.each(badges, function(i, badge) {
$('#badges').append("<h2>New Badge!</h2><p><img class='badge' src='" + badge.image_url + "'><span class='badge-title'>" + badge.name + "</span></p>");
});
},
complete : function() {
$('#preloader').removeClass('active');
}
});
return false;
});
});
#preloader{
background: url(staticpreloader.gif);
}
.active {
background: url(activepreloader.gif);
}
I wrote a blog post about how to do this on a generic document level.
// prepare the form when the DOM is ready
$(document).ready(function() {
// Setup the ajax indicator
$('body').append('<div id="ajaxBusy"><p><img src="images/loading.gif"></p></div>');
$('#ajaxBusy').css({
display:"none",
margin:"0px",
paddingLeft:"0px",
paddingRight:"0px",
paddingTop:"0px",
paddingBottom:"0px",
position:"absolute",
right:"3px",
top:"3px",
width:"auto"
});
});
// Ajax activity indicator bound to ajax start/stop document events
$(document).ajaxStart(function(){
$('#ajaxBusy').show();
}).ajaxStop(function(){
$('#ajaxBusy').hide();
});
The AJAX process starts when you run the $.ajax() method, and it stops when the 'complete' callback is run. So, start your processing imagery/notification right before the $.ajax() line, and end it in the 'complete' callback.
ajaxStart and ajaxStop handlers can be added to any elements, and will be called whenever ajax requests start or stop (if there are concurrent instances, start only gets called on the first one, stop on the last to go). So, it's just a different way of doing global notification if you had, for example, a status spinner somewhere on the page that represents any and all activity.

how to pass a value to jQuery Ajax success-handler

Give the following Ajax call in jQuery:
{
.
.
.
,
getSomeData: function(args, myUrl, foo) {
$.ajax( {
type: "GET",
url: myUrl,
data: args,
async: true,
dataType: 'json',
success: myHandler
});
},
myHandler: function (data, textStatus, oHTTP, foo){ ... }
};
Can value foo be somehow appended to the arguments that are passed to success-handler myHandler? Is there any way to pass a value up to the server on the GET, and have that value come back to the client in a round-trip, reappearing in the success-handler's arguments list? I cannot change the structure of what is returned in data.
If you declare myHandler within the request, you can use a closure.
getSomeData: function(args, myUrl, foo) {
$.ajax( {
type: "GET",
url: myUrl,
data: args,
async: true,
dataType: 'json',
success: function (data, textStatus, oHTTP){ ... }
});
},
this way, foo will be available to you inside the success callback.
If you're $.ajax call is in a class and the success callback is passed a method of that class, it does not work.
EDIT: Here is the answer. Note that I am defining the function ajaxCall as a method in a class. I define this.before, this.error, and this.success as methods of ajaxCall because they can call methods from the superClass.
function main(url){
this.url = url;
this.ajaxCall = function(){
this.before = function(){
//Can call main class methods
};
this.error = function(){
//Can call main class methods
};
this.success = function(data){
//Can call main class methods
};
//This is how you pass class arguments into the success callback
var that = this;
$.ajax({
url: this.url,
type: 'GET',
dataType: 'json',
beforeSend: this.before(),
error: this.error(),
success: function(data){that.succes(data);}
});
//Run internally by calling this.ajaxCall() after it is defined
//this.ajaxCall();
}
//Or externally
var main = new main(SOME_URL);
main.ajaxCall();
#Unicron had the right answer but didn't give a good example. Check this out:
$( 'tr.onCall' ).on( 'click', function( event ) {
let pEvent = function() { return event; } // like a fly in amber...
$.ajax( {
...
success: function( data ) {
let x = pEvent(); // x now equals the event object of the on("click")
}
});
});
By declaring the pEvent function inside the anonymous function that fires on("click"), the event object is "frozen" (encapsulated) in its original context. Even when you call it in the different context of the ajax success function, it retains its original context.
More specific example: I'm going to open a modal dialog (styled Div) on click, but when the dialog is closed I want to return the focus to the element that was clicked to open it in the first place...
$( 'tr.onCall' ).on( 'click', function( event ) {
let rTarget = function() { return event.currentTarget; }
$.ajax( {
url: 'ajax_data.php',
...other settings...
success: function( data ) {
modal_dialog(
data,
{
returnTarget: rTarget(),
...other settings...
}
);
}
});
});
On success, it calls a custom function modal_dialog() (defined elsewhere), passing in an object containing various settings. The returnTarget setting contains the HTML ID attribute of the element that was clicked; so when I close the dialog I can run $(options.returnTarget).focus(); to return focus to that element.

Categories

Resources