Multiple functions on one event not working - javascript

So the logic behind my question:
I have a list like this:
<ul>
<li>
Edit
</li>
<li>
Edit
</li>
<li>
Edit
</li>
</ul>
So when I press Edit link, I must collect data-kms and data-date by using this function, and put them into localStorage:
function setCurrent() {
//Set localStorage items for clicked element
localStorage.setItem('currentKms', $(this).data('kms'));
localStorage.setItem('currentDate', $(this).data('date'));
//Get data
var kms = localStorage.getItem('currentKms');
var date = localStorage.getItem('currentDate');
//Insert data into edit form
$('#editKms').val(kms);
$('#editDate').val(date);
}
And then I want to delete that entry from local storage using this function:
function deleteRun() {
//Get Current Data
var currentKms = localStorage.getItem('currentKms');
var currentDate = localStorage.getItem('currentDate');
var runs = getRunsObject();
var i = 0;
//Loop throuh runs and remove current run from 'runs' object
while (i < runs.length) {
//Remove Current Run
if (runs[i].kms == currentKms && runs[i].date == currentDate) {
runs.splice(i, 1);
alert('Run Deleted');
} else {
alert('Run cant be deleted!');
}
//Save array without current run
localStorage.setItem('runs', JSON.stringify(runs));
i++;
}
//Show Runs Again
$('.original').hide();
showRuns();
//Preventing form from submiting
return false;
}
So basically I have to run 2 functions on 1 event at the same time.
And I'm trying to do it like this:
$('.deleteLink').on('tap', function(){
setCurrent();
deleteRun();
});
But for some reason setCurrent doesn't save the data as it supposed to, it sets values to undefined instead.
But if I run it like this:
$('.deleteLink').on('tap', setCurrent);
It works fine, and it's actually setting correct values to currentKms & currentDate.
So how do I correctly run both of this functions on same event? Because
function(){
setCurrent();
deleteRun();
});
isn't working in my case for some reason.

As per your approach this in the function setCurrent doesn't refers to the element which invoked the event.
You can use .call()
The call() method calls a function with a given this value and arguments provided individually.
$('.deleteLink').on('tap', function(){
setCurrent.call(this);
deleteRun();
});
You can use bind()
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
Code
$('.deleteLink').on('tap', function(){
setCurrent.bind(this)();
deleteRun();
});

Related

Call method inside function

i have a wizard from a metronic theme where I'm trying to call a function to check if my array contains dublicates.
if I remove this part of my code it works without problems.
console.log(this.checkIfArrayIsUnique());
code
var wizard = (<any>$('#m_wizard')).mWizard();
//== Validation before going to next page
wizard.on('change', function(wizard) {
if(wizard.getStep() > 2){
console.log(this.checkIfArrayIsUnique());
}
mApp.scrollTop();
})
Right now my checkIfArrayIsUnique() is just a dummy function
checkIfArrayIsUnique()
{
return true;
}
how can i call a method outside my 'change' event ? So I'm able to run thru my array and confirm it does not have any dublicates.
the problem is the "function(wizard)" call, since it creates a new scope. But your checkIfArrayIsUnique() ist actually outside of this scope.
Try using ES6 function syntax
wizard.on('change',(wizard) => {
if(wizard.getStep() > 2){
console.log(this.checkIfArrayIsUnique());
}
mApp.scrollTop();
})
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
in your change function the variable this point to current function,to use it,you should make this point to out object,you should write like this:
var that = this;
var wizard = (<any>$('#m_wizard')).mWizard();
//== Validation before going to next page
wizard.on('change', function(wizard) {
if(wizard.getStep() > 2){
console.log(that.checkIfArrayIsUnique());
}
mApp.scrollTop();
})

History.JS pass var to above function

I want to pass the var loadurl to the function above. How can i achieve this? (the code below is my function and i want to pass the id to the above code. Any help is appreciated.
$(function() {
// Prepare
var History = window.History; // Note: We are using a capital H instead of a lower h
if ( !History.enabled ) {
// History.js is disabled for this browser.
// This is because we can optionally choose to support HTML4 browsers or not.
return false;
}
// Bind to StateChange Event
History.Adapter.bind(window,'statechange',function() { // Note: We are using statechange instead of popstate
var State = History.getState();
console.log(loadurl);
$('#test').load(loadurl);
/* Instead of the line above, you could run the code below if the url returns the whole page instead of just the content (assuming it has a `#content`):
$.get(State.url, function(response) {
$('#content').html($(response).find('#content').html()); });
*/
});
// Capture all the links to push their url to the history stack and trigger the StateChange Event
$('a').click(function(evt) {
evt.preventDefault();
var loadurl = $(this).attr('id');
History.pushState(loadurl, $(this).text(), $(this).attr('onclick'));
});
});
You can create a global variable at the top of the page, assign it a value within one of your functions, and then use it in another function.

Global Variable Not Assigning between Functions

I am writing an extension for Google Chrome in HTML/Javascript. I am trying to use a global variable to pass information between two functions, however even if I assign my variable in one function it hasn't changed when I read it from the other function.
var type = 0; //define global variable
window.onload=function(){onCreated()}; //set onCreated function to run after loading HTML
function onCreated()
{
chrome.history.search({'text': ''},function(historyItems){gotHistory(historyItems)});//search for historyItems and then pass them to the gotHistory function
}
function gotHistory(historyItems)
{
var idcount=0;//used to increment the ids of each new element added
for(var count=0; count < historyItems.length; count++)//go through each history item
{
chrome.history.getVisits({'url':historyItems[count].url}, function(visitItems){gotVisits(visitItems)}); //search for visitItems for the url and pass the results to gotVisists function (atm all this function does is assign the global variable to =3)
var body = document.getElementById("outputid");//find the body of the HTML
var newt = document.createElement("p");//create a new element
newt.setAttribute("id","url"+idcount);//give it a unique id
newt.innerHTML = historyItems[count].title;//set the text to say the title of the url
if(type != 0)//if the other function was successful, type=3 and the text should be green
{
newt.style.color="green";
}
body.appendChild(newt);//add the new element to the body
idcount++;
}
}
function gotVisits(visitItems)
{
//assign the global variable to be 3
type = 3;
}
But, the elements are NEVER green. They should always be green. This means that in the function gotVisits, type is not being successfully assigned to 3.
Can anyone explain what is going on here?
Cheers,
Matt
p.s I realise the gotVisits function is useless here really, but I'm using it to demonstrate a point. In reality I will use it to pass back useful information to
Rather than:
var type = 0;
Try:
window.type = 0;
Optionally you can also use a closure such as:
(function() {
var type = 0;
var type = 0; //define global variable
window.onload=function(){onCreated()}; //set onCreated function to run after loading HTML
function onCreated()
{
chrome.history.search({'text': ''},function(historyItems){gotHistory(historyItems)});//search for historyItems and then pass them to the gotHistory function
}
function gotHistory(historyItems)
{
var idcount=0;//used to increment the ids of each new element added
for(var count=0; count < historyItems.length; count++)//go through each history item
{
chrome.history.getVisits({'url':historyItems[count].url}, function(visitItems){gotVisits(visitItems)}); //search for visitItems for the url and pass the results to gotVisists function (atm all this function does is assign the global variable to =3)
var body = document.getElementById("outputid");//find the body of the HTML
var newt = document.createElement("p");//create a new element
newt.setAttribute("id","url"+idcount);//give it a unique id
newt.innerHTML = historyItems[count].title;//set the text to say the title of the url
if(type != 0)//if the other function was successful, type=3 and the text should be green
{
newt.style.color="green";
}
body.appendChild(newt);//add the new element to the body
idcount++;
}
}
function gotVisits(visitItems)
{
//assign the global variable to be 3
type = 3;
}
})();
This saves you from polluting the window object, which you should avoid doing anyhow and allows the inner functions access to the type variable.
It should do what you want.
Also the outer function wrapper for your window.onload is redundant, just do:
window.onload = onCreated;
It looks like chrome.history.getVisits executes the callback asynchronously, so you first try to check that variable, and it gets updated later. You can verify this with a pair of console.log messages.
Move the rest of the code inside the callback, so it gets executed at the right time.

Changing the state of a toggle in JavaScript/jQuery

Is it possible to change the state of a toggle function? Like:
myDiv.toggle ... function 1 , function 2
I click on the myDiv element, the function 1 executes
I click again, function 2
I click again, function 1
BUT
Change the state
function 1 again
etc.
But I need to be able to change the state from outside the toggle function.
Here is a javascript object that uses closure to track it's state and toggle:
var TOGGLER = function() {
var _state = true;
var _msg = "function1";
var function1 = function() {
_msg = "function1";
}
var function2 = function() {
_msg = "function2";
}
return {
toggle: (function () {
_state = !_state;
if (_state) {
function1();
} else {
function2();
}
return _msg;
})
}
}();
Here is a jsfiddle that shows how to use it to toggle based with the following jquery: http://jsfiddle.net/yjPKH/5/
$(document).ready(function() {
$("#search").click(function() {
var message = TOGGLER.toggle();
$("#state").text(message);
});
});
The toggle function is meant for simple use cases. Changing the state externally is not "simple" anymore.
You cannot easily/safely (it's internal so it may change during minor versions) access the state variable of the toggle function easily as it's stored in the internal dataset of the element.
If you really want to do it, you can try this code though:
$._data(ELEMENT, "lastToggle" + func.guid, 0);
func is the function you passed to .toggle(), so you need to save this function in a variable. Here's a minimal example: http://jsfiddle.net/xqgrP/
However, since inside the function there's a var guid = fn.guid || jQuery.guid++ statement, I somehow think that the devs actually meant to use guid instead of func.guid for the _data key - in that case a minor update is very likely to break things. And after the fix you'd have to iterate over the data set to retrieve the correct key as there is no way to access the guid from outside.

Linked select boxes coming back 'sel.selectedIndex undefined' on second select area... why?

I've got chained/linked select boxes. Everything works fine if the first select box is chosen, then the second, etc. However. What I want to do is when someone changes the first select area, the second is autopopulated, and the third is also autopopulated based on the first option in the second box.
Here is the code I'm using so far:
function loadTypes(sel)
{
var whichCurr = sel.options[sel.selectedIndex].value;
if(whichCurr.length>0){
var theIndex2 = newAjax2.length;
newAjax2[theIndex2] = new sack();
newAjax2[theIndex2].requestFile = 'getTypes.php?theType='+whichCurr; // Specifying which file to get
newAjax2[theIndex2].onCompletion = function(){ createTypes(theIndex2) }; // Specify function that will be executed after file has been found
newAjax2[theIndex2].runAJAX(); // Execute AJAX function
}
}
function createTypes(theIndex2)
{
var obj3 = document.getElementById('types');
document.getElementById('types').options.length = 0; // Empty city select box
eval(newAjax2[theIndex2].response); // Executing the response from Ajax as Javascript code
getModelList('types');
}
You'll notice at the end of createTypes, the function calls getModelList() which is the function that is called when the SECOND select box is called. It (getModelList()) works fine when manually changing the second box, but when I try to call it from createTypes, it just won't work. Here's the code for getModelList:
function getModelList(sel)
{
var manuCode = sel.options[sel.selectedIndex].value;
var mytext = manuCode.length;
if(manuCode.length>0){
var index = ajax.length;
ajax[index] = new sack();
ajax[index].requestFile = 'getModels.php?manuCode='+manuCode; // Specifying which file to get
ajax[index].onCompletion = function(){ createModelList(index) }; // Specify function that will be executed after file has been found
ajax[index].runAJAX(); // Execute AJAX function
}
}
function createModelList(index)
{
var obj = document.getElementById('sub_types');
$numOpts=(document.getElementById('sub_types').length);
if($numOpts>1){
document.getElementById('sub_types').options.length = 0; // Empty select box
eval(ajax[index].response); // Executing the response from Ajax as Javascript code
$num_of_entries=(document.getElementById('sub_types').length);
if($num_of_entries>1){
}
else
{
hidediv('p_sub_types');
}
}
else
{
document.getElementById('sub_types').options.length = 0; // Empty select box
eval(ajax[index].response); // Executing the response from Ajax as Javascript code
$num_of_entries=(document.getElementById('sub_types').length);
if($num_of_entries>1){
showdiv('p_sub_types');
}
else
{
}
}
}
Again, everything works fine when MANUALLY changing the select box. But when I try to automatically call getModelList() from createTypes() I get an error in Firebug saying: sel.selectedIndex is undefined.
So I'm guessing that it is trying to call that before the select box has been populated... however, I tried adding a pause (of up to 2 seconds!) before calling the function and the same thing happens.
I believe your issue lies in your call to getModelList() at the end of createTypes().
When you're calling getModelList() here you are passing it the string "types" rather than the "types" element (which you've already acquired as "obj3") which it is expecting.
The simplest solution should be to alter your createTypes function to look more like:
function createTypes(theIndex2)
{
var obj3 = document.getElementById('types');
obj3.options.length = 0; // Empty city select box
eval(newAjax2[theIndex2].response); // Executing the response from Ajax as Javascript code
getModelList(obj3);
}
By passing getModelList the element it will have direct access to its properties and should allow your script to function properly.

Categories