Jquery. Call a function when clicking on a link - javascript

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

Related

Accessing a JS variable from a different <script> block

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.

How can i call a function within a js file?

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.

Jquery ajax button click event firing twice?

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.

Uncaught TypeError: undefined is not a function with custom jQuery Plugin

I have made a wrapper plugin for the jquery autocomplete plugin as we use it everywhere on our projects and need to globally change it at times, however whenever i reference the plugin i get the error: Uncaught TypeError: undefined is not a function my pluggin looks like so:
(function ($) {
$.fn.CustomAutocomplete = function (options) {
//Settings
alert("test");
var settings = $.extend({
//Defaults
ContollerMethodLink: "",
ReturnElement: ""
}, options);
$(this).autocomplete({
source: function (request, response) {
var employees = new Array();
$.ajax({
async: false,
cache: false,
type: "POST",
url: ContollerMethodLink,
data: { "query": request.term },
success: function (data) {
for (var i = 0; i < data.length; i++) {
employees[i] = { label: data[i].Key, Id: data[i].Value };
}
}
});
response(employees);
},
select: function (event, ui) {
//fill selected customer details on form
var id = ui.item.Id;
$('#' + settings.ReturnElement).val(id);
}
});
}
})(jQuery);
I then call it like so:
$(document).ready(function() {
$('#AddReportingEmpText').CustomAutocomplete({
ReturnElement: "AddReportingEmpId",
ContollerMethodLink: "#(Url.Action("Method", "Controllers"))",
});
});
However when i try to use this i get the said error in a random empty space right above $(document).ready(function() { if i hard code out the ajax request in the spot where i am currently calling my plugin, everything works fine. Any ideas?
Edit:
worth noting this is my JS File call:
<script src="http://code.jquery.com/jquery-1.9.1.js" type="text/javascript"></script>
<script src="http://code.jquery.com/ui/1.10.2/jquery-ui.js" type="text/javascript"></script>
I then call my plugin file and the debugger shows me it is being properly included
This appears to be well known problem with recent versions of Chrome. Using FF browser will provide with more detailed information about the error

jQuery: Referencing the calling object(this) when the bind/click event is for a class

Thanks for reading this.
I am dynamically generating some data which includes a select drop-down with a text box next to it. If the user clicks the select, I am dynamically populating it (code below). I have a class on the select and I was hoping the following code would work. I tested it with an ID on the select and putting the ONE on the ID I got it to work. However, in changing the code to reference a class (since there will be multiple data groups that include a select with a text box next to it) and $(this), I could not get it to work. Any ideas would be helpful. Thanks
The relevance of the text box next to the select is the second part of the code...to update the text box when an option is selected in the select
.one is so the select is updated only once, then the .bind allows any options selected to be placed in the adjacent text box.
$('.classSelect').one("click",
function() {
$.ajax({
type: "post",
url: myURL ,
dataType: "text",
data: {
'_service' : myService,
'_program' : myProgram ,
'param' : myParams
},
success:
function(request) {
$(this).html(request); // populate select box
} // End success
}); // End ajax method
$(this).bind("click",
function() {
$(this).next().val($(this).val());
}); // End BIND
}); // End One
<select id="mySelect" class="classSelect"></select>
<input type="text">
$(this) is only relevant within the scope of the function. outside of the function though, it loses that reference:
$('.classSelect').one("click", function() {
$(this); // refers to $('.classSelect')
$.ajax({
// content
$(this); // does not refer to $('.classSelect')
});
});
a better way to handle this may be:
$('.classSelect').one("click", function() {
var e = $(this);
$.ajax({
...
success : function(request) {
e.html(request);
}
}); // end ajax
$(this).bind('click', function() {
// bind stuff
}); // end bind
}); // end one
by the way, are you familiar with the load() method? i find it easier for basic ajax (as it acts on the wrapped set, instead of it being a standalone function like $.ajax(). here's how i would rewrite this using load():
$('.classSelect').one('click', function() {
var options = {
type : 'post',
dataType : 'text',
data : {
'_service' : myService,
'_program' : myProgram ,
'param' : myParams
}
} // end options
// load() will automatically load your .classSelect with the results
$(this).load(myUrl, options);
$(this).click(function() {
// etc...
}); // end click
}); // end one
I believe that this is because the function attached to the success event doesn't know what 'this' is as it is run independently of the object you're calling it within. (I'm not explaining it very well, but I think it's to do with closures.)
I think if you added the following line before the $.ajax call:
var _this = this;
and then in the success function used that variable:
success:
function(request) {
_this.html(request); // populate select box
}
it may well work
That is matching one select. You need to match multiple elements so you want
$("select[class='classSelect']") ...
The success() function does not know about this, as any other event callback (they are run outside the object scope).
You need to close the variable in the scope of the success function, but what you really need is not "this", but $(this)
So:
var that = $(this);
... some code ...
success: function(request) {
that.html(request)
}
Thanks Owen. Although there may be a better to write the code (with chaining)....my problem with this code was $(this) was not available in the .ajax and .bind calls..so storing it in a var and using that var was the solution.
Thanks again.
$('.classSelect').one("click",
function() {
var e = $(this) ;
$.ajax({
type: "post",
url: myURL ,
dataType: "text",
data: {
'_service' : myService,
'_program' : myProgram ,
'param' : myParams
},
success:
function(request) {
$(e).html(request); // populate select box
} // End success
}); // End ajax method
$(e).one("click",
function() {
$(e).next().val($(e).val());
}); // End BIND
}); // End One

Categories