Javascript Function scope / accessibility - javascript

I'm no javascript expert and I'm trying to find out how I can ensure my functions are available for all my pages.
My setup:
index.php > my main page where I load my javascript functions
sl.php > a back end script sending html back
$(document).ready(
function ButtonManager()
{
$( "button" ).click(function()
{
$.ajax
({
type: 'POST',
url: 'php/sl.php',
data: 'test=1',
cache: false,
async: false,
dataType: 'html',
success: function(result)
{ $('#mydiv').html(result);
}
});
}
});
</pre>
In my index.php, I have a button that triggers this function and it works fine. Basically it retrieves some html containing other buttons using the same function as the one described above. The problem is that the function declared in index.php does not seem to be known by the html I get back from sl.php
Is there a way to make my ButtonManager function available for the html code that comes back from the server ? The html I get back from the server is inserted in the page where the function is declared.
UPDATE 29/07 :
Here is an example of the buttons I use
TEST
I have such a button in index.php and when I click on it, it posts test=1 to sl.php
In return I get some content that I insert into #mydiv. The process works fine except that buttons included in the sl.php output do not react at all when I click on them.
TJ Crowder:
I have tried your solution (the one without the ready tag) but now even the buttons in index.php don't react any more.
Here is a simplified version to clear any interferences with something else.
var MyApp;
MyApp = MyApp || {};
(function() {
MyApp.ButtonManager = ButtonManager;
function ButtonManager() {
$("button").click(function() {
alert ('oo');
});
}
})();
In the end, the only thing I would like to do is have one location to manage all buttons with sometimes buttons being used in index.php sometimes elsewhere.
Thanks!
Laurent

The code in the question has syntax errors. I'm going to guess your code actually looks like this:
$(document).ready(function() {
function ButtonManager() {
$("button").click(function() {
$.ajax({
type: 'POST',
url: 'php/sl.php',
data: 'test=1',
cache: false,
async: false,
dataType: 'html',
success: function(result) {
$('#mydiv').html(result);
}
});
});
}
});
If so, your ButtonManager function is only accessible within the anonymous function you've passed to ready; it's not accessible outside it.
You can make it a global, but the global namespace is already really crowded, so I'd only create one more global, MyApp or something, and make your functions properties on that object:
// Declare it -- this is a no-op if it's already been declared by another script
var MyApp;
// Use it if it's already initialized by another script, or initialize it if not
MyApp = MyApp || {};
// Your original code
$(document).ready(function() {
// Make ButtonManager a property of MyApp
MyApp.ButtonManager = ButtonManager;
function ButtonManager() {
$("button").click(function() {
$.ajax({
type: 'POST',
url: 'php/sl.php',
data: 'test=1',
cache: false,
async: false,
dataType: 'html',
success: function(result) {
$('#mydiv').html(result);
}
});
});
}
});
Using it:
var mgr = MyApp.ButtonManager();
There, I've left your ButtonManager inside the ready callback on the theory that you have other code in that callback that needs to wait for ready, but just creating the ButtonManager function doesn't need to wait for ready. If you don't have code that needs to wait for ready, you can do this:
// Declare it -- this is a no-op if it's already been declared by another script
var MyApp;
// Use it if it's already initialized by another script, or initialize it if not
MyApp = MyApp || {};
// Use a scoping function to avoid creating more globals
(function() {
// Make ButtonManager a property of MyApp
MyApp.ButtonManager = ButtonManager;
function ButtonManager() {
$("button").click(function() {
$.ajax({
type: 'POST',
url: 'php/sl.php',
data: 'test=1',
cache: false,
async: false,
dataType: 'html',
success: function(result) {
$('#mydiv').html(result);
}
});
});
}
})();
Side note: The overwhelming convention in JavaScript is that function names start with a lowercase letter unless the function is meant to be called via the new operator. So in this case, buttonManager rather than ButtonManager.

I think I have found the solution, TJ Crowder put me on the right track.
In my main page, I have isolated my function to make it global:
<pre>
function ButtonManager()
{ same ajax call }
in my server side output I have added:
<script>
var mgr = ButtonManager();
</script>
</pre>
When I now click on one of the button coming from the server, the function is correctly executed!
Thanks!

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.

Can't access object made by ajax call

I have this ajax request:
$.ajax({
type: "POST",
dataType: "json",
data: dataString,
url: "app/changeQuantity",
success: function(data) {
$('#table').append('<tr><td><a id="uid">click</a></td></tr>');
});
as you can see it makes new row in #table. But this new objects made by ajax are not accessible from next functions. Result from ajax is not a regullar part of DOM, or what is the reason for this strange behavior?
$('#uid').on('click', function () {
alert('ok');
});
Use event delegation:
$(document).on('click','#uid', function () {
alert('ok');
});
Note that ajax calls are asynchronous. So whatever you do with the data you need to do it in a callback within the success function (that is the callback which is called when the ajax call returns successfully).
Jquery on doesn't work like that. Use have to give a parent which not loaded by ajax, and the specify ajax load element like this
$('#table').on('click','#uid' ,function () {
// what ever code you like
});
Is simple and complex at the same time. Simple to solve but complex if you are getting started with javascript...
Your event handler - onclick is being fired and bound to an object that doesnt yet exist.
So when you append the object to the #table, you need to set up your click handler as the object now exists.
So in your success part of the ajax return add the click handler event there.
success: function(data) {
$('#table').append('<tr><td><a id="uid">click</a></td></tr>');
$('#uid').on('click', function () {
alert('ok');
});
});
Or how about you make it dynamic and create a function to do it for you.
function bindClick(id) {
$('#' + id).click(function() {
//Do stuff here
console.log('I made it here' + id);
});
}
Then:
success: function(data) {
$('#table').append('<tr><td><a id="uid">click</a></td></tr>');
bindClick(uid);
});
}
This is a super contrived example but you get the idea you just need to make the rest of it dynamic as well. for example some name and counter generated id number: id1, id2, id3...
Try it like this, add this $('#uid').on('click', function () { into the success
$.ajax({
type: "POST",
dataType: "json",
data: dataString,
url: "app/changeQuantity",
success: function(data) {
$('#table').append('<tr><td><a id="uid">click</a></td></tr>');
$('#uid').on('click', function () {
alert('ok');
});
});
});

JQuery $(this) not accessible after ajax POST?

Let's say I have a bunch of links that share a click event:
Click me
Click me
Click me
Click me
and in the $('.do-stuff').click function I execute a JQuery ajax POST request that updates the database with stuff and I get a successful response. After the ajax is completed, I simply want to change the value of the link text to be whatever I send back from the server...
$('.do-stuff').click(function () {
$.ajax({
type: "POST",
url: "MyWebService.asmx/DoSomething",
data: '{CurrentLinkText: "'+ $(this).text() +'"}',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (result) {
$(this).text(result.d);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert(textStatus);
}
});
});
This invoked just fine and I verified that "result.d" is indeed the text from the server but the text is not changing. I think that the $(this) element is no longer accessible after the AJAX post? What can I do to work around this?
In general when you lose context like that, you can save a reference to the object. Like this:
function clickHandler() {
var that = this;
$.ajax( { url: '#',
success: function (result) {
$(that).text(result.d);
}
);
}
See here:
$(this) inside of AJAX success not working
You can set the context option:
This object will be made the context of all Ajax-related callbacks. By default, the context is an object that represents the ajax settings used in the call ($.ajaxSettings merged with the settings passed to $.ajax). (...)
Example:
$.ajax({
//...
context: this,
success: function(json) {
//...
}
});
or use $.proxy:
$.ajax({
//...
success: $.proxy(function(json) {
//...
}, this)
});
Try:
success: $.proxy(function(result) {
//...
}, this)
There are lots of ways to do this, as you can see from the answers here. Personally, I prefer to construct a function bound to the current value of this:
success: (function(target) {
return function(result) {
$(target).text(result.d);
}
})(this)
It's neat, clean, and $(this) will remain the same as it is in the outer context; i.e. it will be the element that raised the event.
jQuery('#youridvalue').html(result.d);
jQuery('.yourclassvalue').html(result.d);
Use it

execute a function on page load in jquery mobile

I am building a mobile app with Jquery mobile. What you need to know is that I am also working with a content renderer. So I only have one with data-role page. This is what I do in the content renderer. with <%= incBody %> I get the content of my pages.
<body <%=incBodyAttr%>>
<div data-role="page" class="type-index" data-theme="g">
<%=incBody%>
</div>
</body>
I think that was somewhat that you needed to know. Now the real problem.
At the moment I have a function load() You can see it over here.
function load(){
var userId = $("#userId").val();
$.ajax({
url: "~SYSTEM.URL~~CAMPAIGN.URL~/SelligentMobile/Webservice/WebService.asmx/getNieuwtjes",
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: "{'userId':'" + userId + "'}",
success: function (response) {
var nieuwtjes = response.d;
if (nieuwtjes.length > 0) {
$.each(nieuwtjes, function (i, entity) {
$('#nieuwtjesList').append(
$("<li/>").append($("<a/>")
.attr("href",'~PROBE(239)~&NEWSID=' + entity.nieuwtjeId)
.text(entity.nieuwtjeOnderwerp)
)
);
$('#nieuwtjesList').trigger("create");
$('#nieuwtjesList').listview('refresh');
});
}
}
});
}
Now this load is triggered by a button at the moment. But what I want to do is that each time the page loads, its executing this function.
Can anybody help ?
kind regards
Call it from a document ready handler:
$(document).ready(function() {
load();
});
Or, given that you're not passing parameters to load():
$(document).ready(load);
The first way allows you to do other stuff before or after calling load(), should you need to: just add more code into the anonymous function.
See the .ready() doco.
You should use jQuery DOM ready:
$(function() {
// call load() after DOM ready
load();
});
You can also use as
$(document).ready(function() {
load();
})

jQuery plugin bsmSelect doesn't update its values when it is called again and its select options have changed

I'm using bsmSelect jQuery plugin. Basically, what it does is changing the way a select-multiple is rendered to make easier to pick up the options. It hides the select element and shows a list instead.
So, first of all I'm applying the plugin function to my select-multiple element:
$(document).ready(function() {
...
$('#my_select_multiple').bsmSelect({
plugins: [$.bsmSelect.plugins.sortable()],
title: 'Add',
removeLabel: 'Remove'
});
...
});
On the other way, I have another select element (this one is simple) which has an ajax request bind to its change event. This ajax request get new #my_select_multiple options depending on the select simple value. Ajax response is the new HTML for #my_select_multiple options. So I have:
function getNewOptions(val) {
var r = $.ajax({
type: 'GET',
url: /*My URL*/
}).responseText;
return r;
}
...
$(document).ready(function() {
...
$('#my_select_simple').change() {
$('#my_select_multiple').html(getNewOptions($(this).val()));
}
...
});
AJAX is working as expected. New options are got correctly and they are inserted into #my_select_multiple (which is hidden by bsmSelect plugin, but I can check it with Firebug). But bsmSelect didn't realize new changes and doesn't get updated.
So, I think what I want is to reapply $('#my_select_multiple').bsmSelect(); with its new options.
I've been looking around a little bit and here is what I have tried.
1. I've tried to call again the funcion with the success and complete (one at time) of the AJAX request. Didn't work:
function getNewOptions(val) {
var r = $.ajax({
type: 'GET',
url: /*My URL*/,
success: function() { $('#my_select_multiple').bsmSelect(); }
}).responseText;
return r;
}
2. I've tried to bind the function with the on jQuery function. Didn't work:
$('#my_select_simple').on('change', function() {
$('#my_select_multiple').bsmSelect();
});
3. I've tried 1 and 2 removing previosly the HTML generated by bsmSelect. Didn't work.
Thank you very much.
UPDATE: The exact code
First I have a global.js file which apply bsmSelect plugin to some select multiples (.quizzes):
$('.quizzes').bsmSelect({
plugins: [$.bsmSelect.plugins.sortable()],
title: 'Add',
removeLabel: 'Remove'
});
And then, in the php file I define the updateQuizzes function and bind it to the select simple (project_id) change event:
<script type="text/javascript">
function updateQuizzes(project_id) {
var r = $.ajax({
type: 'GET',
url: '<?php echo url_for('event/updateQuizzes')?>'+'<?php echo ($form->getObject()->isNew()?'':'?id='.$form->getObject()->getId()).($form->getObject()->isNew()?'?project_id=':'&project_id=')?>'+project_id,
success: function() { $('.quizzes').bsmSelect({
plugins: [$.bsmSelect.plugins.sortable()],
title: 'Add',
removeLabel: 'Remove'
}); }
}).responseText;
return r;
}
$('#project_id').change(function(){
$('.quizzes').html(updateQuizzes($(this).val()));
});
</script>
As I told, the AJAX request works without problems, but not the calling bsmSelect the second time...
Not sure if this is what the problem is, but you could try
$('#my_select_simple').change() {
$('#my_select_multiple').html(getNewOptions($(this).val())).trigger('change');
}
This triggers a change event on select_multiple, and might fire bsmSelect. I'm not sure what the problem here is exactly, but that's the best I can come up with.
I think you want to set your HTML in the success of the Ajax call, something like:
function loadNewOptions(val) {
$.ajax({
type: 'GET',
url: /*My URL*/,
success: function(data) {
$('#my_select_multiple').html(data).bsmSelect();
}
});
}
And then calling like:
$('#my_select_simple').change() {
loadNewOptions($(this).val());
}
$(document).ready(function() {
$('#my_select_simple').change() {
$('#my_select_multiple').load("your Url", function(){
$('#my_select_multiple').bsmSelect();
});
}
});
something like this should work.
.load will put whatever your url returns into #my_select_multiple
the first parameter is the url to load, and the 2nd is a function to call when it is done. which is where you need to set up your fancy selector.
Ok, I opened a ticket and bsmSelect developer has answered me in minutes. Great!
To let bsmSelect know about its select changes, you have to trigger a change event on the select. There is no need to call bsmSelect again.
So it can be that way:
function loadNewOptions(val) {
var r = $.ajax({
type: 'GET',
url: /*My URL*/,
success: function(data) {
$('#my_select_multiple').html(data).trigger('change');
}
}).responseText;
return r;
}
$('#my_select_simple').change(function() {
loadNewOptions($(this).val());
});

Categories