I'd like to share my variable called str with setInterval function. Its needed to build whole url passing to php script. It works fine with ajax function and GET parameter is passing to php script, but I've got some trouble with setInterval function. I dont know to share the same str variable between these two functions. I enclose my code below:
$(function () {
$(document).ready(function () {
var ultimox;
var ultimoy;
$('#list li a').on('click',function() {
var str = $(this).data('driver');
$.ajax({
url: "live-data.php" + str,
type: 'get',
success: function(DatosRecuperados) {
$.each(DatosRecuperados, function(i,o){
//some body of function
});
setx(DatosRecuperados[(DatosRecuperados.length)-1].x);
sety(DatosRecuperados[(DatosRecuperados.length)-1].y);
$('#container').highcharts({
//this part draws chart
}});
});
});
setInterval(function () {
$.get( "live-data.php?Consultar=1" + str , function( UltimosDatos ) {
//this part draws updated chart
}
});}, 1000);
function getx(){return ultimox;}
function gety(){return ultimoy;}
function setx(x){ultimox=x;}
function sety(y){ultimoy=y;}
});
In JavaScript, scope refers to the current context of your code. Scopes can be globally or locally defined. Understanding JavaScript scope is key to writing good javascript. You’ll need to understand where variables/functions are accessible.
Javascript scope can be thought of as function scoped. You should take the setInterval() function and move it inside $(document).ready(function() { ... });. Since var str; is declared in that function $(document).ready(function() { ... }); the function setInterval can now read str.
I would recommend not polluting the global namespace unless you need to. By this I mean not having the var str; outside of $(document).ready(function() { ... }); . Keep the variable where you need it.
You can have a global variable in JQuery, try the following example.
<script>
var str = "";
$(document).ready(function() {
//do something with 'str'
//e.g. str = 'Some value';
});
function setInterval()
{
//do something with 'str'
//e.g. str = 'Some other value';
}
</script>
Related
I am using the modular design pattern for JS and I keep running into issues when using arguments bound functions. I have a particular function that I would like to bind to different events to keep from having to write the function for each bound event. The only difference in the function, or the argument, is the table that will be updated. The problem is that when I build a function with the arguments I need and pass those arguments to bound events, I get an undefined error, in the console, on load. Keep in mind, I want to stick with this design pattern for the security it offers.
Here is my JS:
var Users = (function(){
var $addRoleForm = $('#addUserRole');
var $rolesTableBody = $('#table-roles tbody');
$addRoleForm.submit(ajaxUpdate(event, $rolesTableBody));
function ajaxUpdate(event, tableName) {
event.preventDefault();
event.stopPropagation();
var url = this.action;
var data = $(this).serialize();
var $this = $(this);
$.ajax({
type: 'POST',
url: url,
dataType: 'json',
data: data,
success: function(data) {
if(data.st === 0){
$messageContainer.html('<p class="alert alert-danger">' + data.msg + '</p>');
setTimeout(function(){
$messageContainer.hide();
}, 7000);
} else {
$messageContainer.html('<p class="alert alert-success">' + data.msg + '</p>');
tableName.fadeOut().html('').html(data.build).fadeIn();
$this.find('input').val('');
setTimeout(function(){
$messageContainer.hide();
}, 7000);
}
},
error: function(xhr, status, error){
console.log(xhr.responseText);
}
});
}
})();
Here is the error I get in the console, on load:
Uncaught TypeError: Cannot read property 'preventDefault' of undefined
I have tried to bind the event like this: $addRoleForm.on('submit', ajaxUpdate(event, $rolesTableBody)); and receive the same results.
Any ideas how to fix this?
You're seeing that issue, because the way you have it written now, ajaxUpdateexecutes, returns undefined and THEN passes undefined to the event listener, so you're basically doing this: $addRoleForm.submit(undefined).
2 Choices here:
1) You can wrap it in an anonymous function:
$addRoleForm.submit(function(event) {
//pass the value of "this" along using call
ajaxUpdate.call(this, event, someValue);
});
$someOtherForm.submit(function(event) {
//pass the value of "this" along using call
ajaxUpdate.call(this, event, someOtherValue);
});
2) You can set the first argument in-advance using bind:
$addRoleForm.submit(ajaxUpdate.bind($addRoleForm, someValue));
$someOtherForm.submit(ajaxUpdate.bind($someOtherForm, someOtherValue));
Using this way, you're binding the value of this to be $addRoleForm, setting the first argument to always be someValue, so it's the same as:
ajaxUpdate(someValue, event) {
//value of "this" will be $addRoleForm;
}
To pass the event, and the custom argument, you should be using an anonymous function call
$addRoleForm.submit(function(event) {
ajaxUpdate(event, $rolesTableBody));
});
This is by far the easiest and most readable way to do this.
What you're doing right now equates to this
var $addRoleForm = $('#addUserRole');
var $rolesTableBody = $('#table-roles tbody');
var resultFromCallingFunction = ajaxUpdate(event, $rolesTableBody); // undefined
$addRoleForm.submit(resultFromCallingFunction);
Where you're calling the ajaxUpdate function, as that's what the parentheses do, and pass the returned result back to the submit callback, which in your case is undefined, the default value a function returns when nothing else is specified.
You could reference the function, like this
$addRoleForm.submit(ajaxUpdate);
but then you can't pass the second argument
The question refers to the Revealing Module pattern. Benefit of using this design is readability. Going with the anon function may work, but defeats the overall purpose of the module pattern itself.
A good way to structure your module to help maintain your scope is to setup helper functions first, then call a return at the end.
Example use case with events:
var User = function() {
// local VARS available to User
var addRoleForm = document.querySelector('#addUserRole');
var rolesTableBody = document.querySelector('#table-roles tbody');
// Helper function 1
function ajaxUpdate(tableName) {
...
}
// Helper function 2
function someFunc() {
...
}
function bindEvents() {
addRoleForm.addEventListener('submit', ajaxUpdate, false);
addRoleForm.addEventListener('click', someFunc, false);
}
function init() {
bindEvents();
}
return {
runMe:init
}
}().runMe();
Helps to "modularize" your workflow. You are also writing your revealing pattern as an IIFE. This can cause debugging headaches in the future. Editing the IIFE to instead invoke via the return is easier to maintain and for other devs to work with and learn initially. Also, it allows you to extend outside of your IFFE into another Module, example:
var Clothes = function() {
function anotherFunc() {
...
}
init() {
User.runMe();
anotherFunc();
}
return {
addClothes: init
}
}().addClothes();
I hope this helps to give you a better understanding of how/when/why to use the JS revealing pattern. Quick note: You can make your modules into IIFE, that's not a problem. You just limit the context of the scope you can work with. Another way of doing things would be to wrap the var User and var Clothes into a main module, and then make that an IIFE. This helps in preventing polluting your global namespace.
Example with what I wrote above:
// MAIN APPLICATION
var GettinDressed = (function() {
// MODULE ONE
///////////////////////////
Var User = function() {
// local VARS available to User
var addRoleForm = document.querySelector('#addUserRole');
var rolesTableBody = document.querySelector('#table-roles tbody');
// Helper function 1
function ajaxUpdate(tableName) {
...
}
// Helper function 2
function someFunc() {
...
}
function bindEvents() {
addRoleForm.addEventListener('submit', ajaxUpdate, false);
addRoleForm.addEventListener('click', someFunc, false);
}
function init() {
bindEvents();
}
return {
runMe:init,
style: someFunc
}
}();
// MODULE TWO
//////////////////////////
var Clothes = function() {
function anotherFunc() {
...
}
init() {
User.style();
anotherFunc();
}
return {
dressUp: init
}
}();
// Define order of instantiation
User.runMe();
Clothes.dressUp();
}());
I have this piece of code in html header:
<script src="../scripts/scripts.js"></script>
<script>
$(document).ready(function() {
window.LastConnection=null;
AjaXUpdateDetails(SetDetailsToHtmlPage);
});
</script>
in scripts.js I have:
var SetDetailsToHtmlPage=function (details_array){
window.LastConnection;
if (window.LastConnection!==null) {
if (window.LastConnection!==details_array.last_connection) {
$("#EStatus").val(details_array.status);
}
}
};
and
function AjaXUpdateDetails(interfaceUpdateFunc){
var ajaxRequest;
if ( (ajaxRequest=getAjaxObject())===false ) return;
ajaxRequest.onreadystatechange = function() {
if(ajaxRequest.readyState == 4) {
var data_array =jQuery.parseJSON(ajaxRequest.responseText);
interfaceUpdateFunc(data_array);
}
};
var queryString = "?id=1";
ajaxRequest.open("GET", "../scripts/AjaXgetDetails.php" + queryString, true);
ajaxRequest.send(null);
}
I read a lot about passing functions as arguments and thought I understood the idea but I keep getting error:
TypeError: interfaceUpdateFunc is not a function
interfaceUpdateFunc(data_array);
Where do I make a mistake?
thanks and regards
Tom
Try checking it before you pass it to AjaXUpdateDetails:
$(document).ready(function() {
window.LastConnection=null;
// verify it is defined here
console.log(SetDetailsToHtmlPage, typeof SetDetailsToHtmlPage)
AjaXUpdateDetails(SetDetailsToHtmlPage);
});
I suspect that will tell you the function is undefined at this point (scope issue). You can probably fix it by changing:
var SetDetailsToHtmlPage=function (details_array) {
to
function SetDetailsToHtmlPage(details_array) {
Here are couple of investigative changes that you can try:
1) The Function expression var SetDetailsToHtmlPage=function (details_array) is not in a function so it has global scope. Because it is an expression then the variable will be "hoisted" which means it is declared before it is assigned to the function. So try declaring it as a function: function SetDetailsToHtmlPage(details_array). This will cause the function declaration including the function to get "hoisted" in the same scope as the document ready event.
2) If that has no effect then try using jQuery document event .load() as opposed to .ready() to see if that has an effect.
$(document).load(function() {
window.LastConnection=null;
AjaXUpdateDetails(SetDetailsToHtmlPage);
});
interfaceUpdateFunc is a param. You could not call by that way.
if (typeof(interfaceUpdateFunc) == "function") {
interfaceUpdateFunc.apply(this, [data_array]);
}
You can check object is a function by this way:
function isFunction(func) {
return Object.prototype.toString.call(func) == '[object Function]';
}
And
if (isFunction(interfaceUpdateFunc)) {
interfaceUpdateFunc.apply(this, [data_array]);
}
$(document).ready(function ()
{
$.ajax(
{
url: "Bibliotheek.xml",
dataType: "xml",
success: function (data)
{
var song = $(data).find('key').filter(function ()
{
return $(this).text().indexOf('Name') != -1;
}).each(function()
{
window['globalVar']= $(this).next('string').text();
console.log(globalVar);
});
}
});
});
I want to use globalVar outside that each loop. But once i put de console.log outside the function. It tells my globalVar is undefined.Is it also possible to use that variable later on in javascript code?
This probably happens, because you loop over an empty list (i.e. it never enters the .each callback). This thing is wrong: .find('key'). It searches for a key tag (which is not HTML, unless you actually are not dealing with HTML?). Perhaps you were looking for .find('.key')?
EDIT: It seems that you want to put console.log outside of ajax call. If you do, then you're out of luck, since you are trying to log a variable that does not exist yet. That's because a in ajax stands for asynchronous, i.e. the piece of code will run later.
EDIT 2: Welcome to asynchronous programming! It seems that you are trying to force ajax to be synchronous, which is wrong and pure eveil. Don't do it. You're code should be similar to this:
var my_fn = function(clb) { // <-- this is callback to be called later
var els = [];
$.ajax({
url: "Bibliotheek.xml",
dataType: "xml",
success: function (data) {
var song = $(data).find('key').filter(function () {
return $(this).text().indexOf('Name') != -1;
}).each(function() {
var el = $(this).next('string').text();
els.push(el);
});
clb(els); // <-- call it now
}
});
};
$(document).ready(function() {
my_fn(function(els) {
console.log(els);
// do coding here
});
});
Define the globalVar outside of the functions...
var globalVar;
var song = {...
console.log(globalVar);//will work here
};
console.log(globalVar);//and, will work here
I'm getting data from server using JQuery and JSON. I defined getBooksDoneFunc
as variable because I need to be able to call this function not only once (when getBooks is done) . Unfortunately, I cannot call getBooksDoneFunc from inside of signInOK as window["getBooksDoneFunc"]();. Why? What is the best way to call this function?
function getBooks(){ return $.getJSON( "bookstore.json" ); }
var getBooksDoneFunc = function(json) {
$.each(json.books, function(i, json){ .......... });
}
getBooks().done(getBooksDoneFunc);
function signInOK(){
window["getBooksDoneFunc"]();
}
PS. The idea for window["getBooksDoneFunc"](); was taken from SO answer
UPDATE:
var booksJSON = {};
window["getBooksDoneFunc"](booksJSON);
getBooksDoneFunc must be called with parameters nevertheless the call to getBooksDoneFunc fails. signInOK is defined outside of $(document).ready(function(){ }); but called inside of it.
Try:
function getBooks(){
return $.getJSON( "bookstore.json" );
}
window.getBooksDoneFunc = function(json) {
$.each(json.books, function(i, json){ .......... });
}
getBooks().done(getBooksDoneFunc);
$(document)ready(function() {
function signInOK(){
var booksJSON = {};
window.getBooksDoneFunc(booksJSON);
}
});
If window["getBooksDoneFunc"](); works, then does getBooksDoneFunc(), the idea of using window is when you want to access a global function but you don't know the function name which is stored in a variable.
In your case, put a hardcoding string is mean less, just do getBooksDoneFunc() is the same, because you already store the function self (not the string of function name) in the variable.
The thing that won't work is that if the variable is not global, please check the scope.
I would do this a bit differently, although I do not really understand the signInOK() function. How will it receive the "json" data. I would reconstruct the getBooks function and rethink the signInOk function. Here's a start:
function getBooks() {
$.getJSON("bookstore.json").done(function (json) {
getBooksDoneFunc(json);
});
}
var getBooksDoneFunc = function(json) {
$.each(json.books, function(i, json){ .......... });
};
...
getBooks();
function signInOK(){
getBooksDoneFunc("some json data");
}
I have the following:
$(function () {
$.ajaxSetup({ cache: false });
var dialogs = {};
var formSubmitHandler = function (e) {
...
}
}
then in another script I try to call
function dialogClick(link) {
$.get(viewUrl + parameters)
.success(function (content) {
if (content.match(/^[eE]rror/)) {
mvcOnFailure(data)
} else {
$.modal({
title: title,
closeButton: true,
content: content,
width: false,
resizeOnLoad: true
}).find('form').submit(formSubmitHandler).end();
}
})
Note that I have cut out parts of the script to make it easy to read. There are no script errors showing just the following error:
In the second script I get an error message saying "SCRIPT5009: 'formSubmitHandler' is undefined' in Internet Explorer.
Am I calling it wrongly? I thought the function would be global and when I check
the script that it is inside of is attached to the page.
No, it's not global; your "formSubmitHandler" function is declared within the "ready" callback in the first block of sample code you posted. It's therefore private to that function.
What you could do, if you really want a global function, is:
window['formSubmitHandler'] = formSubmitHandler;
in the first function. Or, alternatively, you could make it a jQuery "global" function:
$['formSubmitHandler'] = formSubmitHandler;
In that case, you'd get to it as $.formSubmitHandler.
Try moving your function out of the function block e.g
$(function () {
$.ajaxSetup({ cache: false });
var dialogs = {};
}
var formSubmitHandler = function (e) {
...
}
formSubmitHandler only exists within the function scope you declare it, since you used the var variable.
You need to either:
declare dialogClick in the same scope
declare formSubmitHandler in the global scope, using window.formSubmitHandler or simply function formSubmitHandler(){}
formSubmitHandler is a function declared in a scope not visible for the dialogClick() function
So
Either you declare formSubmitHandler as global
or you define the function dialogClick inside document.ready function (and formSubmitHandler is reachable since is in a parent scope)