I created function that recognize which post has been clicked on.
jQuery(document).ready(function() {
jQuery(.recognize-post).on("click", function() {
var clickedButton = jQuery(this).data("id")
console.log("click button with post id: ", clickedButton)
button-id = "recognize-post"
...
...
})
})
}
html
<button id="recognize-post" class="recognize-post" data-id="<?php the_title() ?>">POST</button>
Code above works perfectly and in recognizes the correct post, but I need to pass clickedButton outside of this function and I don't know how to do so.
I need to have it in else if function, this is my attempt
else () {
...
} else if (button-id === "recognize-post") {
console.log(clickedButton)
}
Here the problem comes, clickedButton is underfined and need it to recognize post in exactly the same way how in on click function. Is it possible?
You can make a separate function that takes in the information you want to preserve.
// make a new function
function doSomethingWithTheIdAndBtn(id, btn) {
// take in arguments that represent the id or btn or whatever you need
else () {
...
} else if (id === "recognize-post") {
console.log(btn)
}
}
jQuery(document).ready(function() {
jQuery(.recognize-post).on("click", function() {
var clickedButton = jQuery(this).data("id")
console.log("click button with post id: ", clickedButton)
button-id = "recognize-post"
doSomethingWithTheIdAndBtn(button-id, clickedBtn) // call the function
...
...
})
})
}
So, the issue here is that if you declare a variable function in a given "scope" — in your case, the anonymous function's scope — it will only be defined inside of that scope. If you want to use the variable outside of the function, you need to declare it outside of the function.
So, for instance, if your code was
function foo() {
var myVariable = 0;
}
foo();
// This will throw an error, cuz myVariable is not defined in this scope
console.log(myVariable);
you could fix it by declaring the variable outside of the function's scope
var myVariable; // declare it outside of the function
function foo() {
myVariable = 0; // give it a value inside of the function
}
foo(); // call foo so that myVariable has a value
console.log(myVariable); // this will print 0. Success!
Related
I am trying to execute functions on click, Below is click button on HTML,
Insights.init() will execute on page load will give me some data from server, now with click on button, i need to pass variable to month function to filter data, and with click i want to execute all functions inside Insights()
var Insights = function() {
var initCheckColor = function(vari) {
console.log(vari);
}
var testFunction = function(vari) {
console.log('test');
}
return {
init: function() {
initCheckColor();
testFunction();
}
};
}();
jQuery(document).ready(function() {
Insights.init();
});
function month(vari) {
console.log("hoo");
return {
init: function() {
initCheckColor(vari);
testFunction();
}
};
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Month
Now problem is, i can see "hoo" printed on console when i click on link, but i also want to print it with execution of initCheckColor(vari) function, means i want output two times, but i could not output it,
How can i get output two times?
Problem: Is with this code
function month(vari) {
console.log("hoo");
//this block of code
return {
init: function() {
initCheckColor(vari);
testFunction();
}
};
// upto here
}
When you call the month function you are returning a object with a property named init Note: you are just returning a object and not executing the functions within the property. Also other issue is this property is a function which executes two other function, But those functions are not available in the current scope. As they are equal to Private methods for the Insights object.
Solution: Would be to re initialize the object with data just like how you are doing on page load.
I have fixed your code and added comments in the code where the changes were made.
var Insights = function() {
var initCheckColor = function(vari) {
console.log(vari);
}
var testFunction = function(vari) {
console.log('test');
}
return {
init: function(vari) { // have a input parameter during initialization.
initCheckColor(vari);
testFunction();
}
};
}();
jQuery(document).ready(function() {
Insights.init('something'); // I pass in the string "something" now this will be printed by the initCheckColor function.
});
function month(vari) {
console.log("hoo");
Insights.init(vari); // initialize the Insights object by passing in some value.
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Month
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'm trying to figure out how to make this work.
function foo(a) {
$('#this-button').show();
}
function buttonClicked() {
//get access to var a
}
HTML
<button id="this-button" onclick="buttonClicked();">
This is a simplified version of what I have but the idea is the same.
foo takes a variable, and then makes a button visible. When the button is clicked, I want to do more things with var a.
So like wait until the button is clicked to continue the function?
Can't seem to figure it out.
Thanks
Bind the click handler using jQuery. You can use jQuery.Proxy to bind a as an argument:
function foo(a) {
$('#this-button').show().click( $.proxy( buttonClicked, null, a ) );
}
function buttonClicked(a) {
// Use a here
}
and remove the JavaScript from your html attribute:
<button id="this-button" />
EDIT, if all you want to do is execute some code after the button is clicked, you can do something like this:
function foo(a) {
// Code up here executes before the button is clicked
$('#this-button').show().unbind( 'click.foo' ).one( 'click.foo', function ( ) {
console.log( a );
// This code executes after the click, and has access to a
} );
// Code down here executes before the button is clicked
}
You use an event handler content attribute. Those have access to:
Properties defined in the element (if any)
Properties defined in the form owner of the element 8if any)
Properties defined in the document
Properties in the global object (i.e. global variables).
Therefore, you can add the variable as a property of the element:
function foo(a) {
$('#this-button').show().prop('myProp', a);
}
function buttonClicked(a) {
alert(a);
}
foo(123);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="this-button" onclick="buttonClicked(myProp)">Click me</button>
Of course, using an event handler IDL attribute or an event listener would be a better practice.
This is the reason for a global, either that or create an object with functions that could use closure.
You can always access the global scope:
window.a = a;
But this is generally bad practice. Can you restructure the code so that both places have a available.
Ie
var a = {}; //set a
$("#button").click(function(){
// a is available here
});
foo(a);
HTML
<button id="this-button">
JS
function foo(a) {
$('#this-button').show();
$('#this-button').click(buttonClicked);
function buttonClicked() {
//a can be accesed here
}
}
Put buttonClicked method inside foo to get access of variable a
There's a few different ways to skin this cat but one method is to use a closure to capture the a variable:
var myButton = document.getElementById('this-button');
function foo(a) {
myButton.addEventListener("click", buttonClicked(a));
...
}
function buttonClicked(a) {
return function() {
console.log('buttonClicked', a);
}
}
foo('Success!');
In this case, the function buttonClicked returns a function that captures the value of a when run by the foo function. This resulting function is then passed to the event handler and run when triggered.
See the fiddle here: https://jsfiddle.net/ToddT/ae5h1src/
You could use HTML5 localstorage...
function foo(a) {
$('#this-button').show();
localStorage.setItem("variable_a", a); // variable in localstorage =variable_a
}
function buttonClicked() {
localStorage.getItem('variable_a');
//get access to var a
}
HTML5 localstorage allows you to store data on the client browser, and you can access it via getItem()... more info here: [w3schools], [jenkov.com]
Use closure.
(function(){
var dummy_a;
function foo(a) {
//$('#this-button').show();
dummy_a = a;
}
function buttonClicked() {
//get access to var a
alert(dummy_a)
}
foo(2)
buttonClicked()
})();
var fbToggle = document.getElementById("fbToggle");
and later in the script
fbToggle.addEventListener("click", toggle("fbContainer"));
Console tells me that fbToggle is NULL
This is in the document though.
<input type="checkbox" id="fbToggle">
I wasnt using eventListener before, so maybe there is a special order of declaration i'm missing ?
EDIT :
entire js :
function toggle(target) {
var obj = document.getElementById(target);
display = obj.style.display;
if (display == "none") {display = "block"}
else {display = "none"}
}
function init() {
var fbToggle = document.getElementById("fbToggle");
var twitToggle = document.getElementById("twitToggle");
var pinToggle = document.getElementById("pinToggle");
console.log(fbToggle); // NULL
fbToggle.addEventListener("click", toggle("fbContainer"));
twitToggle.addEventListener("click", toggle("twitContainer"));
pinToggle.addEventListener("click", toggle("pinContainer"));
}
window.onload = init();
HTML is way too long.but JS is in head, called from external file. Also i'm not in quirk mode.
It is not clear where "later in the script" is. If it is in different scope definitely it is not going to work. Suggesting you to keep everything in a global object if possible so that you can access from different places in the script.
window.globals = {};
window.globals.fbToggle = document.getElementById("fbToggle");
window.globals.fbToggle.addEventListener("click", function () {
toggle("fbContainer")
});
function toggle(container) {
alert(container);
}
http://jsfiddle.net/ST938/
Another point is addEventListener expects a function or function idenitifier, NOT a function call.
addEventListener("click", toggle("fbContainer")); // wrong
addEventListener("click", toggle); // correct
So if you want to pass a parameter
window.globals.fbToggle.addEventListener("click", function () {
toggle("fbContainer")
});
function toggle(container) {
alert(container);
}
In JavaScript, putting brackets after a function name causes it to be called. If you want to reference a function without calling it you must not put brackets after the name:
window.onload = init(); // this calls init() immediately
window.onload = init; // this correctly stores init in window.onload
The same applies to toggle(). If you need to pre-specify some of the arguments you can wrap it in an anonymous function:
fbToggle.addEventListener("click", function() { toggle("fbContainer"); });
or you can use bind:
fbToggle.addEventListener("click", toggle.bind(null, "fbContainer"));
I want to have one button, functioning as both the "start" and "stop" button for some reoccurring timed events.
To do this, I can have a global variable on the top of everything:
toggleOn = false;
And then, inside of <button onClick="..., I can have:
toggleOn =! toggleOn;
foo();
function foo() {
// do my stuff
if (toggleOn) {
setTimeout(foo, 5000);
}
}
But the problem is, I must not use a global variable to complete the same task. How should I do it? Is there a persist variable that can carry a value outside its scope?
This is an example for something where closures are great feature of the language.
(function()
{
var active = false;
myButton.addEventListener('click', function myButtonClick(event)
{
if (active) {
// recursion..?
setTimeout(myButtonClick, 5000);
}
active = !active;
}
})();
More on closures here.
Use the javascript module pattern. Something like this:
var handler = function () {
var private_state = true;
return function() {
private_state = !private_state;
if (private_state) {
// Do something
}
}
}();
Use handler as your button onclick handler.
Earlier answers already noted that you could use closures to store a "private" variable that would keep track of state. Alternatively you could use HTML5 data to store this as well.
html
<button data-toggleOn="false">Click me!</button>
javascript
button.addEventListener('click', function() {
var toggleOn = this.dataset.toggleOn = !JSON.parse(this.dataset.toggleOn);
if (toggleOn) {
// do stuff!
}
});
and if you're using jQuery..
$('button').click(function() {
var toggleOn = !$(this).data('toggleOn');
$(this).data('toggleOn', toggleOn);
});