I have a JavaScript file AppForm.js, which I wish to reinitialize after a successful ajax post response.
The file itself contains, among others
(function(namespace, $) {
"use strict";
var AppForm = function() {
// Create reference to this instance
var o = this;
// Initialize app when document is ready
$(document).ready(function() {
o.initialize();
});
};
var p = AppForm.prototype;
p.initialize = function() {
// Init events
this._enableEvents();
this._initRadioAndCheckbox();
this._initFloatingLabels();
this._initValidation();
};
p._enableEvents = function () {
//blah blah blah
e.preventDefault();
};
p._initRadioAndCheckbox = function () {
};
p._initFloatingLabels = function () {
};
p._initValidation = function () {
};
window.materialadmin.AppForm = new AppForm;
}(this.materialadmin, jQuery)); // pass in (namespace, jQuery):
How can I do that?
$.ajax({
url: path, type: "POST", cache: "false",
dataType: "html",
contentType: "application/json; charset=utf-8",
traditional: true,
data: JSON.stringify(postData)
}).success(function (data) {
$("#products-list").html(data);
//**PERFORM INIT OF JS FILE**
}).error(function (data) {
});
Thanks to Dan's answer the solution is pretty close but the events are not working since e.preventDefault(); is called.
And here is the full script
(function(namespace, $) {
"use strict";
var AppForm = function() {
// Create reference to this instance
var o = this;
// Initialize app when document is ready
$(document).ready(function() {
o.initialize();
});
};
var p = AppForm.prototype;
// =========================================================================
// INIT
// =========================================================================
p.initialize = function() {
// Init events
this._enableEvents();
this._initRadioAndCheckbox();
this._initFloatingLabels();
this._initValidation();
};
// =========================================================================
// EVENTS
// =========================================================================
// events
p._enableEvents = function () {
var o = this;
// Link submit function
$('[data-submit="form"]').on('click', function (e) {
e.preventDefault();
var formId = $(e.currentTarget).attr('href');
$(formId).submit();
});
// Init textarea autosize
$('textarea.autosize').on('focus', function () {
$(this).autosize({append: ''});
});
};
// =========================================================================
// RADIO AND CHECKBOX LISTENERS
// =========================================================================
p._initRadioAndCheckbox = function () {
// Add a span class the styled checkboxes and radio buttons for correct styling
$('.checkbox-styled input, .radio-styled input').each(function () {
if ($(this).next('span').length === 0) {
$(this).after('<span></span>');
}
});
};
// =========================================================================
// FLOATING LABELS
// =========================================================================
p._initFloatingLabels = function () {
var o = this;
$('.floating-label .form-control').on('keyup change', function (e) {
var input = $(e.currentTarget);
if ($.trim(input.val()) !== '') {
input.addClass('dirty').removeClass('static');
} else {
input.removeClass('dirty').removeClass('static');
}
});
$('.floating-label .form-control').each(function () {
var input = $(this);
if ($.trim(input.val()) !== '') {
input.addClass('static').addClass('dirty');
}
});
$('.form-horizontal .form-control').each(function () {
$(this).after('<div class="form-control-line"></div>');
});
};
// =========================================================================
// VALIDATION
// =========================================================================
p._initValidation = function () {
if (!$.isFunction($.fn.validate)) {
return;
}
$.validator.setDefaults({
highlight: function (element) {
$(element).closest('.form-group').addClass('has-error');
},
unhighlight: function (element) {
$(element).closest('.form-group').removeClass('has-error');
},
errorElement: 'span',
errorClass: 'help-block',
errorPlacement: function (error, element) {
if (element.parent('.input-group').length) {
error.insertAfter(element.parent());
}
else if (element.parent('label').length) {
error.insertAfter(element.parent());
}
else {
error.insertAfter(element);
}
}
});
$('.form-validate').each(function () {
var validator = $(this).validate();
$(this).data('validator', validator);
});
};
// =========================================================================
// DEFINE NAMESPACE
// =========================================================================
window.materialadmin.AppForm = new AppForm;
}(this.materialadmin, jQuery)); // pass in (namespace, jQuery):
UPDATE 1
I added window.materialadmin.AppForm.Initilize at the ajax response but the events are not working
UPDATE 2
And here is the code that does not work after the postback.
$(".ProductOnlyForDemonstation, .IncludeInMainPage, .Active")
.on('click', 'button', function(){
$('.sweet-overlay').toggle();
if (jQuery("#FORM").valid()) {
var id = $(this).attr("data-id");
$.post("/product/DemoIncludeActive", {
"Id": id,
"ProductOnlyForDemonstation": $("#ProductOnlyForDemonstation-" + id).is(':checked'),
"IncludeInMainPage": $("#IncludeInMainPage-" + id).is(':checked'),
"Active": $("#Active-" + id).is(':checked'),
},
function (data) {
}).success(function (data) {
}).error(function () {
});
}
});
You can wrap your code in a global function.
(function(namespace, $) {
"use strict";
window.main = function() {
var AppForm = function () {
// ...
};
};
window.main(); // you can initialize it here
)(this.materialadmin, jQuery);
And execute it if the response is successful.
.success(function (data) {
$("#products-list").html(data);
//**PERFORM INIT OF JS FILE**
window.main();
}).error(function (data) {
});
Edit: It looks like you're exposing the initialize method on a global object. You can just call that init method when the AJAX response completes.
.success(function (data) {
$("#products-list").html(data);
//**PERFORM INIT OF JS FILE**
window.materialadmin.AppForm.initialize();
}).error(function (data) {
});
Related to UPDATE 2
Try to register your events with delegation:
$(document).on(
'click',
'.ProductOnlyForDemonstation button, .IncludeInMainPage button, .Active button',
function() {
// Your code
}
);
I suppose you're loading something and render new page content after response, so previously registered events are not attached to new elements. With delegation you'll get your events working even after elements were added to DOM dynamically (if they match with delegating selector), because events are attached to document and bubbled from your buttons. You can attach event deeper in the DOM than document itself, but to the element containing your dynamic content (in other words: to closest element that will not be overriden after completing request).
PS. You can also add some unique class to all .ProductOnlyForDemonstation button, .IncludeInMainPage button, .Active button and delegate events to that class (shorter definition)
some checks for the events to work after postback
1)using $("#products-list").html(data) will remove all the events attached to child elements of #products-list.
So either a)attach events once on "#products-list" only with event-delegation In jQuery, how to attach events to dynamic html elements?
or b)reattach events on every child after using $("#products-list").html(data)
2) dont use .html() because it also removes all jquery data and events on children. update independent children elements instead.
I had experienced same issue like you. After reinitializing events,all events are not working properly.
I have tried lots and finally i have found issue.when i am reinitializing all control, all events are rebind.
so they are not fired properly.
so please unbind all events related to your control and then init all control agian and bind all event.
Updated answer
if you are using jQuery 1.7 or onwarads then add following code:
$(".ProductOnlyForDemonstation, .IncludeInMainPage, .Active").off();
$('[data-submit="form"]').off('click');
$('textarea.autosize').off('focus');
$('.floating-label .form-control').off('keyup change');
//-----------------
//**PERFORM INIT OF JS FILE**
before this line.
//**PERFORM INIT OF JS FILE**
and you are using jquery below 1.7 then use following code:
$(".ProductOnlyForDemonstation, .IncludeInMainPage, .Active").unbind();
$('[data-submit="form"]').unbind('click');
$('textarea.autosize').unbind('focus');
$('.floating-label .form-control').unbind('keyup change');
//-----------------
//**PERFORM INIT OF JS FILE**
before this line.
//**PERFORM INIT OF JS FILE**
for more help related to unbind click here.
for more help related to off click here.
i hope this will help.
In order to call a function you should take into account the following points below:
The function should be defined in the same file or one loaded before the attempt to call it.
The function should be in the same or greater scope then the one trying to call it.
So, the following example should work:
You declare function fnc1 in first.js, and then in second you can just have fnc1();
first.js :
function fnc1 (){
alert('test');
}
second.js :
fnc1();
index.html :
<script type="text/javascript" src="first.js"></script>
<script type="text/javascript" src="second.js"></script>
You could add the line namespace.initialize = p.initialize; at the end of your code :
(function(namespace, $) {
"use strict";
/* ....... */
// =================================================
// DEFINE NAMESPACE
// =================================================
namespace.AppForm = new AppForm;
namespace.initialize = p.initialize;
}(this.materialadmin, jQuery)); // pass in (namespace, jQuery):
Then, p.initialize becomes available globally as materialadmin.initialize, and you can call it from another file like this :
materialadmin.initialize();
Maybe two solutions
First solution
Create a file js with your functions who will reload.
<script language="text/javascript">
function load_js()
{
var head= document.getElementsByTagName('head')[0];
var script= document.createElement('script');
script.type= 'text/javascript';
script.src= 'source_file.js';
head.appendChild(script);
}
</script>
And in your success :
.success(function (data) {
$("#products-list").html(data);
load_js();
}).error(function (data) {
});
2nd Solution
Like the first solution : Create a file js with your functions who will reload.
Use use getScript instead of document.write - it will even allow for a callback once the file loads.
Description: Load a JavaScript file from the server using a GET HTTP
request, then execute it.
So you can try this :
.success(function (data) {
$.getScript('your-file.js', function() {
}).error(function (data) {
});
or simply :
jQuery.getScript('my-js.js');
You will try, and tell me if that helps.
It should be simple by printing content of this at top of your ajax url script :
<script src="your-js-to-be-initialized.js"></script>
Your jquery ajax code will remain the same. You just need to print the script on each request so that it is reinitialized and binds to your elements.
$.ajax({
url: path.php, type: "POST", cache: "false",
dataType: "html", contentType: "application/json; charset=utf-8",
traditional: true,
data: JSON.stringify(postData)
}).success(function (data) {
$("#products-list").html(data);
//**PERFORM INIT OF JS FILE**
//path.php should echo/print the <script src="your-js-to-be-initialized.js">
}).error(function (data) {
});
I looked at your edit history and saw you did
p._enableEvents = function () {
var o = this;
// Link submit function
$('[data-submit="form"]').on('click', function (e) {
e.preventDefault();
var formId = $(e.currentTarget).attr('href');
$(formId).submit();
});
// Init textarea autosize
$('textarea.autosize').on('focus', function () {
$(this).autosize({append: ''});
});
};
If this is still how you enable your events, I suspect the cause might be you have more than one subscription on form click and textarea focus after reinitializing on your ajax callback. I suggest try only do other init tasks, and exclude event bindings in your callback function.
Try make it like this:
(function($) {
"use strict";
var materialadmin = {};
var AppForm = function() {
//closure
var self = this;
(function(){
//todo: init events
};)();
//<your AppForm class's props here...>
};
materialadmin.Init = function(){
//create instance of AppForm calss for materialadmin object
materialadmin.appForm = new AppForm();
}
return materialadmin;
//*}(jQuery)); // syntax mistake, i'm sorry)).*
})(jQuery);
$(document).ready(function(){
materialadmin.Init();
});
$.ajax({
url: path,
type: "POST",
cache: "false",
dataType: "html",
contentType: "application/json; charset=utf-8",
traditional: true,
data: JSON.stringify(postData),
success: function (data) {
$("#products-list").html(data);
materialadmin.Init();
},
error: function(){
alert('error')}
});
As you're using jQuery validator, you can use Validator's resetForm method in order to reset your form.
For this purpose, you can expose a reset method like follows:
p.reset = function () {
// Reset managed form
$('.form-validate').data('validator').resetForm();
// Reset custom stuff
this._initRadioAndCheckbox();
this._initFloatingLabels();
};
Note that in order to reset your form correctly after posting your request, you need to isolate event binding from the init stuff, for instance the following event binding should move from _initFloatingLabels to _enableEvents:
// Link submit function
$('[data-submit="form"]').on('click', function (e) {
e.preventDefault();
var formId = $(e.currentTarget).attr('href');
$(formId).submit();
});
Finally, you just have to call window.materialadmin.AppForm.reset() in your POST request's callback.
Related
I need to access a js variable declared in one block of a html page into another block of the same html page just so I can stop a ajax call that is being made, but I don't know how can I access a variable that was declared into another block. I can't merge the two blocks, everything else is on the table.
<script>
$(function() {
var term = new Terminal('#input-line .cmdline', '#container output');
term.init();
});
</script>
<script>
term.ajaxHandler.abort();//but how can I access the variable term from the block above,this will be inside a button later
</script>
Thanks in advance
The way your code example is described, it's not possible to reuse that variable. Because it is not bound to the window object, it's bound to the function that is self-executed. It's an example of a "safe" way of libraries not intervening with your own code.
You can however, since I guess by the syntax it's jQuery, hook into the jQuery ajax handling. Based on your requirements, to stop an ajax call, you need to listen to all ajax requests.
You could take a look at the jQuery ajax hooks, https://api.jquery.com/category/ajax/.
You could end up with something like:
$(document).ajaxSend(function(event, xhr, settings){
if (settings.url === "/your/url/to/abort") {
xhr.abort();
}
});
just declare var term above the function declaration
var term
function test1(){
term = 'hello there'
test2()
}
function test2(){
console.log(term)
}
test1()
ok, I managed to solve, basically I created a function only to abort the ajax request like this:
this.abortAjax = () => {
requestHandler.abort();
}
and then accessing it within terminal.js itself using the term object that was instantiated beforehand. After working around the code I was able to keep everything inside the terminal script and not splitted in the two parts, getting something like this:
function ShowLoadingScreen () {
var customElement = $("<div>", {
"class" : "btn btn-danger btn-lg",
"text" : "Abort",
"onclick": "term.abortAjax()"
});
$.LoadingOverlay("show", {
//image : "/static/loading.gif",
background : "rgba(204, 187, 0, 0.8)",
imageAnimation : "rotate_right",
//imageAutoResize : true,
text : "Loading...",
custom : customElement
});
}
function request (command) {
...
requestHandler = $.ajax({
url: _url,
beforeSend: function () { ShowLoadingScreen(); }, // <Show OverLay
type: 'GET',
dataType: 'json',
success: function (response) {
...
},
complete: function () { HideLoadingScreen(); } //<Hide Overlay
}).fail(function (jqXHR, textStatus, error) {
...
});
ShowLoadingScreen();
}
Thanks, everyone.
Given: There is a JS function that calls the list of cities. Included in the header as a js file
GeoIPModule.prototype.loadCities = function(callback) {
var self = this;
if (!this.citiesLoaded) {
$.ajax({
url: self.http_host + 'index.php?route=extension/module/geoip/getList',
dataType: 'html',
success: function(html) {
self.chooseBlock.html(html);
var input = self.chooseBlock.find('.geoip-popup-input');
self.autocomplete(input, self.chooseBlock.find('.geoip-body'));
input.siblings('ul.dropdown-menu').css({'maxHeight': 300, 'overflowY': 'auto', 'overflowX': 'hidden'});
input.focus();
self.citiesLoaded = true;
callback.apply();
}
});
}
};
Task: It is necessary to call the function, i.e. call up a list of cities by clicking on the link in any part of the document
Trying to do this:
ССЫЛКА
<script type="text/javascript">
$("#load-сities").click(function(e) {
GeoIPModule.prototype.loadCities();
});
</script>
But I get the error: ReferenceError: GeoIPModule is not defined
Complete script https://jsfiddle.net/3L604e7m
If you want GeoIPModule to be globally available, you can set the property on the window. Currently, it is only visible inside the immediately-invoked function expression.
window.GeoIPModule = function(o, el){
//...
}
JSFiddle
I have a Employee page which shows list of employees with an edit option. On clicking the edit button jquery-ajax is used to fetch the data from the server.
The problem is when I click the edit button the event is firing twice.
I am using a seperate js file and is referring the file to the main page.The script was working fine until i moved it to the seperate js file.
The Jquery script is
//ajaxGet on edit button click
$(document).on('click', '.editRole', ajaxGet);
var ajaxGet = function (e) {
var spinner = $(this).parent('div').find('.spinner');
var href = $("#editMenuSettings").data("url");
var menuRoleId = $(this).data('id');
spinner.toggle(true);
var options = {
type: "GET",
url: href,
data: { menuRoleId: menuRoleId }
};
$.ajax(options).success(function (data) {
spinner.toggle(false);
$(".modal-body").html(data);
$(".modal").modal({
backdrop: 'static'
});
});
$.ajax(options).error(function (data) {
spinner.toggle(false);
toastr.error("Oops..Some thing gone wrong");
});
return false;
};
You call $.ajax twice.
At lines
$.ajax(options).success(function(data)...
$.ajax(options).error(function(data)...
you actually make two different AJAX calls - one with success callback only, another one with error callback.
In your case, your call should look like this:
var options = {
type: "GET",
url: href,
data: { menuRoleId: menuRoleId }
};
$.ajax(options)
.success(function (data) {
spinner.toggle(false);
$(".modal-body").html(data);
$(".modal").modal({
backdrop: 'static'
});
})
.error(function (data) {
spinner.toggle(false);
toastr.error("Oops..Some thing gone wrong");
});
return false;
It will set both callbacks to the single AJAX call and execute this one.
In my plug-in I need to wrapp all sidebar's children in a div to let them overflow but if those elements are loaded dynamically the function does not work and I don't know either how to make it work.
The code is:
<div class="sidebar">
</div>
var $sidebar = $( '.sidebar' );
$sidebar.load( 'external-page.ext' );
$sidebar.MyPlugin();
$.fn.MyPlugin = function() {
this.wrapInner( '<div />' );
});
If those elements are not loaded dynamically there is no problem.
Firstly the code was:
$sidebar.wrapInner( '<div/>' );
and this just works fine if elemens are not loaded dynamically, so I tried this way:
var children = $sidebar.children();
$( document ).on( 'load', children, function() {
$( this ).wrapAll( '<div />' );
});
but, of course it does not work.
Can you please help me?
I thought that this rule would have worked this time too but it didn't. What did I mistake?
You can find the whole code here.
And a demo here
MORE DETAILS
I want to handle this issue from the inside, not from the outside! I don't know if users will load content dinamically or not. that's the point.
So there is a way to handle this issue inside the plugin and not outside?
From the manual
http://api.jquery.com/load/
Callback Function
If a "complete" callback is provided, it is executed after
post-processing and HTML insertion has been performed. The callback is
fired once for each element in the jQuery collection, and this is set
to each DOM element in turn.
Try the following code and see if this works:
$sidebar.load( 'external-page.ext', function() { $sidebar.MyPlugin(); } );
Thanks.
$.load() makes an ajax call to load the data ,
So there is a possibility that your this.wrapInner( '<div />' ) method has invoked before any data is loaded inside the div.sidebar.
Make sure this.wrapInner( '<div />' ) is called after all data has been loaded successfully using the complete callback.
$.load() trigger callback for each div ,call your plugin from callback
$sidebar.load('http://fiddle.jshell.net/vikrant47/ncagab2y/1/show/', function () {
$(this).MyPlugin();
}
});
DEMO
OR
If you are using $.load() only to load inside multiple elements then you could probably use one of the more powerful jQuery ajax methods (i.e., get() or post() or ajax()).
$.get('http://fiddle.jshell.net/vikrant47/ncagab2y/1/show/', {}, function(data) {
$sidebar.html(data).MyPlugin();
});
DEMO using $.get() Method
UPDATE-
Answer to the comment-
You should not have to worry about weather user gonna call your plugin like this $sidebar.load(...).MyPlugin().User must be aware enough about how to handle asynchronous methods.
You can not make your plugin work until there is some data inside div.slider
but ,you can add ajax loading functionality inside your plugin like -
$(document).ready(function () {
$.fn.MyPlugin = function (options) {
var $elem=this;
var init = function () {
options.load = $.extend({}, $.fn.MyPlugin.defaultOptions.load, options.load);
load();
}
//adding load method to load data dynamically
var load = function () {
if (!options.load.url) {
alert("url can not be empty");
} else {
$.ajax({
url: options.load.url,
type: options.load.type,
data: options.load.data,
success: function (response) {
options.load.success.call(this, response);
$elem.html(response).wrapInner('<div class="wrapper"/>');//wrap after data has been loaded successfully
},
error : function (jqXHR, textStatus, errorThrown) {
alert("error occured" + textStatus + " ," + errorThrown)
}
})
}
}
init();
}
$.fn.MyPlugin.defaultOptions = {
load: {
tye: "get",
data: {},
success: function () {}
}
};
Now use your plugin like-
var $sidebar = $('.sidebar');
$sidebar.MyPlugin({
load: {
url: 'http://fiddle.jshell.net/vikrant47/ncagab2y/1/show/'
}
});
});
DEMO with load
Try adding adding below piece to plugin . Added at lines 84 - 110 at gist .
var target = $sidebar.get(0);
// create an observer instance
var observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
// do stuff when
// `childList` modified
// i.e.g.,
$.each(mutation.addedNodes, function (k, v) {
$(v)
.wrapInner('<div data-'
+ dataName
+ '="sub-wrapper"></div>')
})
});
});
// configuration of the observer:
var _config = {
childList: true
};
// pass in the target node, as well as the observer options
observer.observe(target, _config);
jsfiddle http://jsfiddle.net/guest271314/s5wzptc8/
See MutationObserver
Apologies, a total newb here. How can I load other plugins, and let other separate scripts function after loading an ajax generated page? This is my curent code:
jQuery(document).ready(function($) {
var $mainContent = $("load-content"),
siteUrl = "http://" + top.location.host.toString(),
url = '';
$(document).delegate("a[href^='"+siteUrl+"']:not([href*='/wp-admin/']):not([href*='/wp-login.php']):not([href$='/feed/'])", "click", function() {
if($.browser.msie){
var myie="/"+this.pathname;
location.hash = myie;
//alert(location.hash);
}else{
location.hash = this.pathname;
}
return false;
});
$("#searchform").submit(function(e) {
$search = $("#s").val();
$search = $.trim($search);
$search = $search.replace(/\s+/g,'+');
location.hash = '?s='+$search;
e.preventDefault();
});
$(window).bind('hashchange', function(){
url = window.location.hash.substring(1);
if (!url) {
return;
}
url = url + " #content";
$('html, body, document').animate({scrollTop:0}, 'fast');
$mainContent.fadeOut(500, function(){$('#content').fadeOut(500, function(){
$("#loader").show();});}).load(url, function() {
$mainContent.fadeIn(500, function(){
$("#loader").hide(function(){ $('#content').fadeIn(500);});});});
});
$(window).trigger('hashchange');
});
How can embedded objects on pages retain their functionality? Mainly videos, slideshows and other media that use javascript like
video js (html5 video player)
vimeo
and
portfolio slideshow for wordpress
When you load ajax-generated markup it will not retain the functionality it had before. In your example above, you're initialising things when the DOM is ready to be acted upon. In order to make sure any plugins, etc, are running after you perform the ajax request you need to reinitialise them.
Given your code sample above, I'd recommend a little restructuring. For example, you could create a function called init which you could call to initialise certain plugins:
function init () {
$("#plugin-element").pluginName();
}
jQuery(document).ready(function () {
// Initialise the plugin when the DOM is ready to be acted upon
init();
});
And then following this, on the success callback of you ajax request, you can call it again which will reinitialise the plugins:
// inside jQuery(document).ready(...)
$.ajax({
type: 'GET',
url: 'page-to-request.html',
success: function (data, textStatus, jqXHR) {
// Do something with your requested markup (data)
$('#ajax-target').html(data);
// Reinitialise plugins:
init();
},
error: function (jqXHR, textStatus, errorThrown) {
// Callback for when the request fails
}
});