I need to use the value of a boolean variable to trigger an action, and I will use this in several occasions, then is very important I do in the best way.
I already search and found a way to use object.watch, like this:
let test1 = {on: false};
teste1.watch('on', function (prop, oldval, newval) {
if (teste1.on === true) {
$('#bot').toggleClass('switch-bck');
} else {
$('#bot').toggleClass('switch');
}
return newval;
});
interact('#bot2')
.on('down', function (event) {
event.currentTarget.classList.toggle('switch');
event.preventDefault();
if (teste1.on) {
teste1.on = false;
} else {
teste1.on = true;
}
document.getElementById('demo').innerHTML = teste1.on;
})
.on('up', function (event) {
event.currentTarget.classList.toggle('switch');
event.preventDefault();
document.getElementById('demo').innerHTML = teste1.on;
});
document.getElementById('demo').innerHTML = teste1.on;
This almost works.
When I change the state of teste1.on the first 2 times works well. But after this take the double of changes of teste1.on for the
$('#bot').toggleClass('switch-bck');
be activated. But I see that teste1.on change correctly because I see its value with
document.getElementById('demo').innerHTML = teste1.on;
If I change return newval to return oldval or even remove it, the change that I want happens perfectly, but the value that I se with
document.getElementById('demo').innerHTML = teste1.on;
remain freeze or show "undefined".
Any help? Or even a way to do this without using .watch?
Related
I have 2 event listeners and they both push the element that is clicked into 2 separate arrays. These console.log in the event listener functions as expected, however when I pass them into a move function they both return undefined.
I've tried it with just passing the element that is selected into the function as well with the same result.
document.querySelectorAll('img').forEach(function(el) {
el.addEventListener('click' , function(params) {
el.classList.add('selected')
selectedPieces.push(el)
console.log(selectedPieces)
moveBy(selectedPieces)
})
})
document.querySelectorAll('.square').forEach(function(el) {
el.addEventListener('click', function() {
el.classList.add('target')
targetPieces.push(el)
console.log(targetPieces)
moveBy(targetPieces)
})
})
function moveBy(selected,target) {
console.log(selected)
console.log(target)
}
So I did create a work around in this. It involved sending the addEventListeners to their own functions, then adding them to an array, then sending that array to it's own function which then allowed me to move things around.
Only thing wrong with this version is that it only works one time, so I'm currently working through what is causing it to only fire once.
document.querySelectorAll('img').forEach(function(el) {
el.addEventListener('click' , addselected)
})
document.querySelectorAll('.square').forEach(function(el) {
el.addEventListener('click', addtarget)
})
function addselected(selected){
console.log('---addselected---')
var select = selected.path[0]
moveList.push(select)
}
function addtarget(target){
console.log('---addtarget---')
if (target.path.length === 7){
var tar = target.path[1]
}else{
var tar = target.path[0]
}
moveList.push(tar)
moveBy(...moveList)
}
function moveBy(...moveList) {
console.log('---moveBy---')
let moveTarg = moveList[2]
let moveSel = moveList[0]
if (typeof moveTarg === 'undefined') {
console.log('not working')
}else{
moveTarg.appendChild(moveSel)
moveList = []
}
console.log(moveList)
}
well
function moveBy(selected,target) {
console.log(selected)
console.log(target)
}
has two paramaters.
moveBy(targetPieces)
but you pass only one parameter in.
I have a function
function formSubmitListener() {
$(".js-form").submit(event => {
event.preventDefault();
let input = fetchInput();
validateInput(input);
if (isValid) {
serverCall()
}
});
}
validateInput returns a isValid boolean of true (if all fields on a form have been filled out) that I need to make available for the if statement. If at all possible I want to prevent the use of a global variable.
How do I make the boolean available ?
function formSubmitListener() {
$(".js-form").submit(event => {
event.preventDefault();
let input = fetchInput();
let isValid = validateInput(input);
if (isValid == true) {
serverCall()
}
});
}
this might be what you want. set the validateInput(input) function call to a variable and use that variable since it will store the true/false.
or another way by putting the direct function in the if where it checks whats returned
function formSubmitListener() {
$(".js-form").submit(event => {
event.preventDefault();
let input = fetchInput();
if (validateInput(input)) {
serverCall()
}
});
}
I'm having some trouble with booleans and scope. I have set a global boolean to false, upon a function the boolean turns true. if the boolean is true I want another function to run. However the boolean is only changed in the scope of the function that makes it true and is still false globally. Thus the following function which needs the boolean to be true is not running.
The first part of my code looks something like this:
let threePick= false;
let twoPick = false;
let onePick = false;
let found = false;
var startGame = false;
function selector() {
$("#threebut").click(function () {
if (found === false) {
found = true;
onePick = true;
twoPick = true;
var input = this;
input.disabled = true;
}
})
$("#onebut").click(function () {
if (found === false) {
found = true;
threePick = true;
twoPick = true;
var input = this;
input.disabled = true;
}
})
$("#twobut").click(function () {
if (found === false) {
found = true;
threePick = true;
onePick=true;
var input = this;
input.disabled = true;
};
});
};
selector();
function enemy() {
$("#twobut").click(function () {
if (twoPick === true){
var input = this;
input.disabled = true;
startGame = true;
}
});
$("#threebut").click(function() {
if (threePick === true){
input.disabled = true;
startGame = true;
}
});
$("#twobut").click(function() {
if (twoPick === true){
var input = this;
input.disabled = true;
startGame = true;
}
});
}
enemy();
Notice that the enemy(); changes the startGame boolean to true
Now in the next part of my code:
function gameStart(){
if (startGame === true){
var button = $('<button/>', {
text: 'Attack'
})
$('#atkButton').append(button);
}
}
gameStart();
I want the function to run when the boolean is true but the boolean only changes locally. I know that accessing local variables is not possible but is there any way around this or an alternative I could use?
P.S I apologise for my inefficient code I've only been doing javascript for a few days.
Any help is appreciated!
gameStart() is called immediately after it is defined and only once. At this time the value of startGame is false.
enemy() sets up eventlisteners for clicks on buttons #threebut and #twobut. Only when one of these buttons is clicked is the value of startGame set to true. If gameStart() is called thereafter it will see that startGame is true.
Your two functions selector and enemy define event handlers for the click action on elements in your HTML. Unless you click on those elements these event handlers, and attached functions, are not called.
Your id=twobut element has three different event handlers attached which will all fire when that element is clicked.
Normally in jQuery you use $(document).ready(function() { ... }); in which you can call selector(); and enemy(); so this run when the DOM is properly loaded and the event handlers can be attached successfully.
Maybe add the HTML from your page to create a working example?
I am using the following code jsFiddle:
function Field(args) {
this.id = args.id;
this.name = args.name ? args.name : null;
this.reqType = args.reqType ? args.reqType : null;
this.reqUrl = args.reqUrl ? args.reqUrl : null;
this.required = args.required ? true : false;
this.error = args.error ? args.error : null;
this.elem = document.getElementById(this.id);
this.value = this.elem.value;
this.elem.addEventListener('blur', this, false);
this.elem.addEventListener('focus', this, false);
}
// FormTitle is the specific field like a text field. There could be many of them.
function FormTitle(args) {
Field.call(this, args);
}
Field.prototype.getValue = function() { return Helpers.trim( this.value ) };
Field.prototype.blur = function (value) {
alert("blur");
};
Field.prototype.focus = function (value) {
alert("focus");
};
Field.prototype.handleEvent = function(event) {
var prop = event.type;
if ((prop in this) && typeof this[prop] == "function")
this[prop](this.value);
};
inheritPrototype(FormTitle, Field);
var title = new FormTitle({name: "sa", id: "title"});
function inheritPrototype(e, t) {
var n = Object.create(t.prototype);
n.constructor = e;
e.prototype = n
}
if (!Object.create) {
Object.create = function (e) {
function t() {}
if (arguments.length > 1) {
throw new Error("Object.create implementation only accepts the first parameter.")
}
t.prototype = e;
return new t
}
}
The problem is that the 'blur' event is fired every time the field is brought to focus, which is opposite of what you'd expect. This is despite the fact that the focus event isn't even mentioned in the code. The problem is that I cannot replicate this problem in jsFiddle but the problem is happening in IE.
Also, on jsFiddle, there is another problem. The focus event is triggered multiple times...
Is there a possible explanation for this and/or a solution?
Updated:
Bonus question (and last on this, promise).
I added a function addEvent to dynamically add events to form fields instead of adding them all directly in the parent constructor. This is the jsFiddle for it. I am trying to call the function but it doesn't seem to work. What might I be doing wrong?
The alert in your focus handler immediately removes focus away from the field as soon as it gains focus. The loss of focus triggers the blur. It is odd that the blur comes first.
If you change the alerts to console.log (or something that does not steal focus), you will see that the events fire correctly.
http://jsfiddle.net/rsKQq/4/
I want to set different value to self.selectedTitleId() in knockoutjs when self.selectedQueryId changes, so i have added a subscribe to selectedQueryId.
I have another computed variable self.text which format the self.selectedTitleId with other variables.
My problem is , when i change the selectedQueryId value from UI, computed function gets called first, followed by subscribe call. Because of this, the text that i am trying to display always holds the previous selection value.
I want to hold the self.text computed function execution until selectedTitleId.subscribe function is completed so that self.selectedTitleId has current value.
Can someone help me? Thanks for your time!
Below is the html component which is used to bing selectedTitleId value with UI. backend js always shows the 'backendName' as value, even though i tried to set a different value using self.selectedTitleId("newValue").
html:
var sformat = (function() {
var pattern = /\{\{|\}\}|\{(\d+)\}/g;
return function () {
var parameters = arguments;
if(parameters[0]) {
console.log(parameters[0])
return parameters[0].replace(pattern, function (match, group) {
var value;
if (match === "{{")
return "{";
if (match === "}}")
return "}";
value = parameters[parseInt(group, 10) + 1];
return value ? value.toString() : "";
});
}
};
});
function test() {
return sformat.apply(this, arguments);
}
self.selectedTitleId = ko.observable('');
self.text = ko.computed(function () {
console.log("inside text function")
if (self.selectedTitleId && self.selectedQueryId()) {
console.log(self.selectedTitleId)
self.displayField = test(self.selectedTitleId, self.selectedQueryId(),self.queryValue());
}else if(self.selectedTitleId && self.selectedQueryId() && self.queryGreaterValue() && self.queryLesserValue()){
self.displayField = test(self.selectedTitleId, self.selectedQueryId(),self.queryValue(),self.queryGreaterValue(),self.queryLesserValue());
}
return self.displayField;
});
self.selectedQueryId.subscribe(function (newValue) {
$.getJSON("json/queries.json", function (allData) {
var mappedData = $.map(allData, function (item) {
if(item.DisplayName == "Price"){
if(newValue == "range") {
self.selectedTitleId(item.RangeBackEndFieldName);
console.log("range");
console.log(item.RangeBackEndFieldName); //Prints new string
console.log(self.selectedTitleId()); //Print old value-
}else if(newValue == "$gt:" || newValue == "$lt:"){
self.selectedTitleId(item.BackendFieldName);
});
}
}
});
});
});
Unless there is something else you are not telling us, it doesn't make sense for selectedTitleId to be a ko.computed. Just use a regular observable:
self.selectedTitleId = ko.observable();
self.selectedQueryId.subscribe(function (newValue) {
$.getJSON("json/queries.json", function (allData) {
var mappedData = $.map(allData, function (item) {
if(item.DisplayName == "Price"){
if(newValue == "range") {
self.selectedTitleId(item.RangeBackEndFieldName);
});
}else if(newValue == "$gt:" || newValue == "$lt:"){
self.selectedTitleId(item.BackendFieldName);
});
}
}
});
});
});
Now when selectedTitleId is changed in your callback, it should trigger text to re-evaluate.
The problem with your original wasn't that it was updating text first, it was that it wasn't re-evaluating when you changed selectedTitleId. See here:
if (self.selectedTitleId() && self.selectedQueryId()) {
This means your computed property is dependent on both selectedTitleId and selectedQueryId, updating either will cause the function to run again. But in your original code, you completely replaced self.selectedTitleId with an entirely new function, but your computed is still dependent on the old one (which is unchanged).