Problems with unbinding a function by handler - javascript

I have html like this:
<div>
<input type="checkbox" id="checkbox", checked="checked"/>
<label for="checkbox">Copy values</label>
</div>
<div>
<input id="source" type="text"/>
</div>
<div>
<input id="target" type="text"/>
</div>
And I'm trying to implement jQuery code to copy value from source input to target one, only when the checkbox is checked. Here's my code:
var checkbox = $("#checkbox");
var source = $("#source");
var target = $("#target");
var bindFunction = function () {
var copyValue = function () {console.log("asd");
target.val(source.val());
}
if (checkbox.is(":checked")) {
source.bind("keyup", copyValue);
}
else {
source.unbind("keyup", copyValue);
}
}
checkbox.bind("change", bindFunction);
bindFunction();
However, it does not work as expected - for some reason the copyValue function doesn't get unbound. What am I doing wrong?
Here's a jsFiddle.

You need to move the copyValue function outside of the bindFunction function.
This is because it was creating a new instance of copyValue each time the checkbox was clicked so the unbind was running against a different function than the one that was originally bound.
var copyValue = function () {
console.log("asd");
target.val(source.val());
}
var bindFunction = function () {
if (checkbox.is(":checked")) {
source.bind("keyup", copyValue);
}
else {
source.unbind("keyup", copyValue);
}
}
checkbox.bind("change", bindFunction);
bindFunction();
http://jsfiddle.net/5b93H/1/

Related

Convert Button onClick function to jQuery

Currently have code in HTML, but would like to convert it to JavaScript. You can see the codes below:
I'd like to convert the following to JQuery (instead of in HTML):
<button id="1" onclick="swapStyleSheet('style1.css')">Button1</button>
<button id="2" onclick="swapStyleSheet('style2.css')">Button2</button>
<button id="3" onclick="swapStyleSheet('style3.css')">Button3</button>
The above code triggers this:
var swapStyleSheet = function (sheet) {
document.getElementById('pagestyle').setAttribute('href', sheet);
storebackground(sheet);
}
var storebackground = function (swapstylesheet) {
localStorage.setItem("sheetKey", swapstylesheet); //you need to give a key and value
}
var loadbackground = function () {
document.getElementById('pagestyle').setAttribute('href', localStorage.getItem('sheetKey'));
}
window.onload = loadbackground();
Thanks!
You could try something like this..
// Here we get all the buttons
var button = document.getElementsByTagName('button');
// We loop the buttons
for (var i=0; i<button.length; i++){
// Here we add a click event for each buttons
button[i].onclick = function() {
alert("style"+this.id+".css");
//swapStyleSheet("style"+this.id+".css"); you can do it something like that;
}
}
var swapStyleSheet = function (sheet) {
//document.getElementById('pagestyle').setAttribute('href', sheet);
//storebackground(sheet);
}
var storebackground = function (swapstylesheet) {
// localStorage.setItem("sheetKey", swapstylesheet); //you need to give a key and value
}
var loadbackground = function () {
//document.getElementById('pagestyle').setAttribute('href', localStorage.getItem('sheetKey'));
}
//window.onload = loadbackground();
<button id="1">Button1</button>
<button id="2" >Button2</button>
<button id="3" >Button3</button>
No need for JQuery
Looks like you are just looking for click event handlers. Here's a version using jQuery. I commented out the code dealing with the missing 'pagestyle' element and localstorage to prevent js errors in the StackOverflow snippet.
var swapStyleSheet = function (sheet) {
console.log( 'sheet: ' + sheet ); // look at the console when you press a button
//document.getElementById('pagestyle').setAttribute('href', sheet);
//storebackground(sheet);
}
var storebackground = function (swapstylesheet) {
//localStorage.setItem("sheetKey", swapstylesheet); //you need to give a key and value
}
var loadbackground = function () {
//document.getElementById('pagestyle').setAttribute('href', localStorage.getItem('sheetKey'));
}
window.onload = loadbackground();
$( '#1' ).on( 'click', function() {
swapStyleSheet('style1.css');
});
$( '#2' ).on( 'click', function() {
swapStyleSheet('style2.css');
});
$( '#3' ).on( 'click', function() {
swapStyleSheet('style3.css');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="1">Button1</button>
<button id="2">Button2</button>
<button id="3">Button3</button>
<button id="1" class='changestyle' data-stylesheet = "style1.css">Button1</button>
<button id="2" class='changestyle' data-stylesheet = "style2.css">Button2</button>
<button id="3" class='changestyle' data-stylesheet = "style3.css">Button3</button>
jQuery
$(function(){
$(".changestyle").on("click", function(){
$("#pagestyle").attr("href", $(this).data('stylesheet'));
})
})

How do I add/remove a list-item onClick using Angular.js?

I am new to Angular.js and what I'm trying to do is adding a lis-item every time the user clicks on #create-new-rule but the below doesn't seem to be working.
Also, when the user click on li .delete I want that list-item to be removed from the DOM as well as from the this.rules array.
app.js
app.controller('RuleController', function()
{
function Rule ()
{
this.name = 'untitled';
this.delete = function ()
{
console.log('removed from DOM as well as from this.rules array');
};
};
this.rules = [];
this.addRule = function ()
{
this.rules.push(new Rule());
};
});
index.html
<div id="rule-controller" ng-controller="RuleController as RuleCtrl">
<ul id="rules">
<li class="rule" ng-repeat="rule in RuleCtrl.rules">
<input type="text" ng-value="rule.name"/>
<div class="delete" ng-click="rule.delete()">delete</div>
</li>
</ul>
<div id="create-new-rule">
<div ng-click="RuleCtrl.add()">create new rule</div>
</div>
</div>
Your method for adding is called addRule() but from the view you are calling add(). Try changing that. Furthermore, to remove you can use splice, but you would need to get a reference to this outside of the Rule function in order to access the array.
E.g.index.html:
<div ng-click="RuleCtrl.addRule()">create new rule</div>
Controller:
var app = angular.module('myApp', []);
app.controller('RuleController', function()
{
var self = this;
function Rule ()
{
this.name = 'untitled';
this.delete = function ()
{
var index = self.rules.indexOf(this);
self.rules.splice(index,1);
};
};
this.rules = [new Rule()];
this.addRule = function ()
{
this.rules.push(new Rule());
};
});

Get the element in a JQuery Callback

I'm having trouble getting the element in a jQuery Callback function. I have tried various suggestions of $(this) and $(this.element) with no success.
$.fn.onTypeFinished = function (func) {
$(this).bind("keypress", onKeyPress)
function onKeyPress() {
setTimeout(onTimeOut, 500);
}
function onTimeOut() {
func.apply();
}
return this;
};
$(".user-input").onTypeFinished(function () {
var ntabindex = parseFloat($(this.element).attr('tabindex'));
ntabindex++;
$('input[tabindex=' + ntabindex + ']').focus();
});
I have been thinking I need some way to pass a reference to this to the callback function but no other similar posts seem to suggest that route.
Here is a JSFiddle of what I am trying to do. The gist of the functionality is I'm trying to auto advance to the next input according to tabindex.
http://jsfiddle.net/helfon/fdu8xw0h/2/
Thanks
From your code it looks like you want to pass the element on which the keypress has occurred as this to the callback.
For that to happen you need to pass the correct context to the timeout handler, for which we can use .bind() as shown below.
Also to make the timer work correctly some other corrections are also made.
$.fn.onTypeFinished = function(func) {
$(this).bind("keypress", onKeyPress)
function onKeyPress() {
var onTypeFinished = $(this).data('onTypeFinished');
if (!onTypeFinished) {
onTypeFinished = {};
$(this).data('onTypeFinished', onTypeFinished);
}
clearTimeout(onTypeFinished.keytimer);
onTypeFinished.keytimer = setTimeout(onTimeOut.bind(this), 500);
}
function onTimeOut() {
func.apply(this);
}
return this;
};
$(".user-input").onTypeFinished(function() {
//$('input[tabindex=3]').focus();
var ntabindex = parseFloat(this.getAttribute('tabindex'));
ntabindex++;
$('input[tabindex=' + ntabindex + ']').focus();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input id="1" tabindex=1 class="user-input">
<input id="2" tabindex=2 class="user-input">
<input id="3" tabindex=3 class="user-input">
<input id="4" tabindex=4 class="user-input">
As per the logs, it seems that your this keyword inside the jQuery fn is pointing to the window object instead, I've bound the functions as follows and passed this in your apply, and got it working so that this points to the input elements instead:
$.fn.onTypeFinished = function (func) {
var time;
$(this).each(function () {
$(this).on('keypress', onKeyPress);
});
function onKeyPress() {
clearTimeout(time);
time = setTimeout(onTimeOut.bind(this), 500);
}
function onTimeOut() {
func.apply(this);
}
return this;
};
$(".user-input").onTypeFinished(function () {
//$('input[tabindex=3]').focus();
var ntabindex = parseFloat($(this).attr('tabindex'));
++ntabindex;
$('input[tabindex=' + ntabindex + ']').focus();
});
http://jsfiddle.net/fdu8xw0h/9/
You have to also iterate over the array of elements as your selector is returning an array of inputs, so you have to handle them separately, otherwise your event will occur only once, i've tested it and it goes from the first input to the second and then it stops working. With the approach i've pasted here it will go from input to input.
You should understand that this changes whenever you change scope. Always var $this = $(this) to lock it down.
$.fn.onTypeFinished = function (func) {
var $this = $(this);
$this.bind("keypress", onKeyPress);
function onKeyPress() {
setTimeout(onTimeOut, 500);
}
function onTimeOut() {
func($this); //I would personally send this, like how you do $.each(function(count, element){})
}
return this;
};
$(".user-input").onTypeFinished(function (t) {
var ntabindex = parseInt($(t).attr('tabindex')) + 1; //You should parse int here
$('input[tabindex=' + ntabindex + ']').focus();
});
Of course, you can simplify the above more into:
$.fn.onTypeFinished = function (func) {
var $this = $(this);
$this.bind("keypress", onKeyPress);
function onKeyPress() {
setTimeout(function(){
func($this);
}, 500);
}
return this;
};
$(".user-input").onTypeFinished(function (t) {
$('input[tabindex=' + String(parseInt($(t).attr('tabindex')) + 1) + ']').focus();
});
The jsfiddle: http://jsfiddle.net/vimxts/fdu8xw0h/6/

Merging 2 javascripts into one

I have 2 javascripts working but want to merge them into one.
The purpose of the script is to make a checkbox that changes the a varable for the refresh rate.
Script 1 (works as expected)
window.onload = function () {
var input = document.querySelector('input[type=checkbox]');
function check() {
if (input.checked) {
var timeout = "10000";
} else {
var timeout = "999999";
}
document.getElementById('result').innerHTML = 'result ' + timeout;
}
input.onchange = check;
check();
}
<input type="checkbox" value="1" />Checkbox
<br/>
<br/>
<span id="result"></span>
Script 2 (works as expected)
var timeout = 10000;
var action = function() {
$('#content').load('/arduino/refresh');
};
setInterval(action, timeout);
I tought I could just merge them together and let them live happily ever after so I created the following script: (it shows the checkbox but checking/unchecking does not change the refresh rate)
window.onload = function () {
var input = document.querySelector('input[type=checkbox]');
function check() {
if (input.checked) {
var timeout = "10000";
} else {
var timeout = "999999";
}
var action = function() {
$('#content').load('/arduino/refresh');
};
}
input.onchange = check;
check();
}
setInterval(action, timeout);
<input type="checkbox" value="1" />Checkbox
<br/>
<br/>
<span id="result"></span>
Any advise?
In the combined script, setInterval is not called within the check event handler. The local variable timeout is modified, but the new value is never used to actually change the refresh rate.
Also, use clearInterval and setInterval together when changing the refresh rate.

onscroll div in a JavaScript object

i want to build a div with scroll, that when you scroll this div, it will active anothe function.
i need to build this in a Object.
there is any way to do this?
i write here an example source (that not work) of what i want.
<script type="text/javascript">
function onsc(divName, divChange) {
this.play = function() {
window.onload = function() {
document.getElementById(divName).onscroll = function() {
this.scroll(n)
}
};
}
this.scroll = function(n) {
document.getElementById(divChange).innerHTML = "you scroll!";
}
}
c[1] = new onsc("div1", "div1_i").play();
</script>
<div id="div1_i">this div will change when you scroll</div>
<div id="div1" style="background:#C6E2FF; width:300px; height:200px; overflow-y:scroll;">
<p style="height:800px;">txt</p>
</div>
Your code was nearly there. I made a few changes and put into a JSFiddle for you.
I added comments at what you missed. Most importantly the context of this changes when you entered into that function on the onscroll event.
JavaScript
function onsc(divName, divChange) {
// First of all make `this` inherit to below functions
var self = this;
this.play = function () {
document.getElementById(divName).onscroll = function() {
// Changed this to call the parent and place the correct DIV
self.scroll(divChange)
}
}
this.scroll = function (n) {
document.getElementById(divChange).innerHTML = "you scroll!";
}
}
c = new onsc("div1", "div1_i").play();
Demo
Have a look at my JSFiddle: http://jsfiddle.net/bJD8w/2/

Categories