By click I add record from one collection to another. But a lot of times it adds an empty object. Here I tried to add some timeout and check if there is an _id attribute, and the amount of empty objects has reduced, but there are still some empty objects, when click too often. Is this a known bug? Is there any way to get around this?
timeout = false;
Template.clients.events({
'click': function() {
if(typeof this._id !== 'undefined' && !timeout) {
timeout = true;
TempCol.insert(this, function() {
var tmt = 300 + parseInt(Math.floor(Math.random() * (300 + 1)));
setTimeout(function() { timeout = false; }, tmt);
});
}
}
});
UPD: Actually, it gets the job done, but the question is still open: is that a bug or what?
Related
The problem: I want to call a value from a nested method outside of its parent method. In other words, I want the output from "console.log(someObjects[i].valueChecker);" to be either "true" or "false." However, it is just returning the function itself.
What I've done so far: So I have been scouring the web/stack overflow for a solution, but either I haven't found a solution, or I just can't make sense of it. I think it has something to do with "closures," and most of the solutions to problems I've seen have been to return from the submethod, and then return the submethod from the parent method. However, every time I've tried this, I've just encountered numerous errors-- either another submethod suddenly doesn't exist, or the code runs, but the output is still a function. I wonder if having multiple methods affects the issue.
Context: I'm making a platformer game, and there are multiple types of the same enemy. I want to check for collision between the player and weapon and thusly need some values from the enemy function (I don't want to use the word "class," but I'm not sure about the appropriate terminology). I'm much more familiar with Java though, so it is frustrating me to not be able to create a separate class and just have a method to give me values back.
//assume all the other html/main stuff is already set up
var temp = {
create: c4,
update: u4
}
MyObject = function(value) {
this.value = value; //passed in value
var magicNumber = 4; //local value initialized/declared
this.valueChecker = function() {
//return boolean
return this.value == this.magicNumber;
}
this.otherValueChecker = function() {
//return boolean
return (this.value + 1) == this.magicNumber;
}
}
//just make the space bar tied to a boolean
var someKeyPress;
function c4() {
someKeyPress = game.input.keyboard.addKey(Phaser.Keyboard.A);
}
var someObjects = [];
//... later on in the program, presuming key already coded
function u4() {
//add a new MyObject to array someObjects
if (someKeyPress.isDown) {
//check with various random numbers between 3 to 5
someObjects.push(new MyObject(game.rnd.integerInRange(3, 5)));
}
//run through MyObject(s) added to someObjects, and see if any match number
for (var i = 0; i < someObjects.length; i++) {
console.log(someObjects[i].valueChecker);
}
}
/* current output
ƒ () {
//return boolean
return this.value == this.magicNumber;
}
*/
Try
console.log(someObjects[i].valueChecker())
Because I see the value checker as a function
this.valueChecker = function()
i'm facing difficulty in understanding what this following code does. could anyone here please help me out in understanding this piece of code?
var PnPResponsiveApp = PnPResponsiveApp || {};
PnPResponsiveApp.responsivizeSettings = function () {
// return if no longer on Settings page
if (window.location.href.indexOf('/settings.aspx') < 0) return;
// find the Settings root element, or wait if not available yet
var settingsRoot = $(".ms-siteSettings-root");
if (!settingsRoot.length) {
setTimeout(PnPResponsiveApp.responsivizeSettings, 100);
return;
}
}
var PnPResponsiveApp = PnPResponsiveApp || {};
The above line ensures that the PnPResponsiveApp variable gets its old value if it already exists, otherwise it's set to a new object.
PnPResponsiveApp.responsivizeSettings = function () {
Here, a new function is created.
// return if no longer on Settings page
if (window.location.href.indexOf('/settings.aspx') < 0) return;
If the URL of the current page isn't the settings page, then the function exits immediately.
// find the Settings root element, or wait if not available yet
var settingsRoot = $(".ms-siteSettings-root");
This gets all elements with a class of .ms-siteSettings-root.
if (!settingsRoot.length) {
setTimeout(PnPResponsiveApp.responsivizeSettings, 100);
return;
}
If any elements were found (if the length of the node list is not zero), then call the PnPResponsiveApp.responsivizeSettings function in 100 milliseconds.
Very easy code basically, I'll explain what's going on:
var PnPResponsiveApp = PnPResponsiveApp || {};
This is very common way to see if the variable is already defined and if not, avoid throwing error and equal it to an empty object, It's used in many frameworks and library, very safe way to check if the var is there already... look at here for more info: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators
PnPResponsiveApp.responsivizeSettings = function () {};
This is basically a simple function but attached to the object PnPResponsiveApp - if just responsivizeSettings = function () {}; it's attached to window Object
if (window.location.href.indexOf('/settings.aspx') < 0) return;
this is Checking if the Link in the linkbar has settings.aspx - indexOf return -1 if it doesn't contain the string, so if it's not settings.aspx it returns -1 that's smaller than 0 and then the whole function return ... the second return basically return undefined
var settingsRoot = $(".ms-siteSettings-root");
This is basically look for all element with class of ms-siteSettings-root and equal them to variable settingsRoot, it could be a single DOM or multiple...
if (!settingsRoot.length) {
and this basically check if any DOM element has ms-siteSettings-root class, length return a Number, so if it's not there, it returns 0, if there is return 1,2,3 etc... and 0 is equal to False in JavaScript and bigger than 0 is equal to True, so this way we can check if it's there...
setTimeout(PnPResponsiveApp.responsivizeSettings, 100);
so if the settingsRoot is there, we execute this function block and with setTimeout we wait 100ms... setTimeout always works in this manner, setTimeout(function(), time); and the same return happens at the end...
Hope it's informative enough...
Take a look at the working CodePen here: http://codepen.io/djskinner/pen/JdpwyY
// Animation start events push here
var startBus = new Bacon.Bus();
// Animation end events push here
var endBus = new Bacon.Bus();
// Balance updates push here
var balanceBus = new Bacon.Bus();
// A Property that determines if animating or not
var isAnimating = Bacon.update(false,
[startBus], function() { return true; },
[endBus], function() { return false; }
);
// Only update the displayBalance when not animating
var displayBalance = Bacon.update(0,
[balanceBus.holdWhen(isAnimating)], function(previous, x) {
return x;
}
);
setTimeout(function() {
var streamTemplate = Bacon.combineTemplate({
balance: displayBalance
});
// Uncommenting this block changes the way the system behaves
// streamTemplate.onValue(function(initialState) {
// console.log(initialState);
//})();
// Print the displayBalance
streamTemplate.onValue(function(v) {
console.log(v.balance);
});
});
Pressing the balance button generates a new random number. A Property is created that uses holdWhen to restrict balance updates coming through until the isAnimating Property becomes false.
If I was interested in getting the initial state of streamTemplate, I might get the value and immediately unsubscribe:
streamTemplate.onValue(function(initialState) {
console.log(initialState);
})();
However, once I do this the displayBalance Property behaves differently and I no longer receive updates.
Why would this seemingly inert change make such a drastic different to the system? Surely the behaviour of the system shouldn't be dependent on whether someone has subscribe and unsubscribed to the streamTemplate at some point in the past?
This behaviour has been confirmed as a bug that has been fixed in 0.7.67.
See here for details.
I am fairly new to knockout and am trying to figure out how to put two pieces that I understand together.
I need:
Items that are dependent on each other.
Input value validation on the items.
Example:
I have startTime in seconds, duration in seconds, and stopTime that is calculated from startTime + duration
startTime cannot be changed
duration and stopTime are tied to input fields
stopTime is displayed and entered in HH:MM:SS format
If the user changes stopTime, duration should be calculated and automatically updated
If the user changes duration, stopTime should be calculated and automatically updated
I can make them update each other (assume Sec2HMS and HMS2Sec are defined elsewhere, and convert between HH:MM:SS and seconds):
this.startTime = 120; // Start at 120 seconds
this.duration = ko.observable(0);
// This dependency works by itself.
this.stopTimeFormatted = ko.computed({
read: function () {
return Sec2HMS(this.startTime + parseInt(this.duration()), true);
},
write: function (value) {
var stopTimeSeconds = HMS2Sec(value);
if (!isNaN(stopTimeSeconds)) {
this.duration(stopTimeSeconds - this.startTime);
} else {
this.duration(0);
}
},
owner: this
});
Or, I can use extenders or fn to validate the input as is shown in the knockout docs:
ko.subscribable.fn.HMSValidate = function (errorMessage) {
//add some sub-observables to our observable
var observable = this;
observable.hasError = ko.observable();
observable.errorMessage = ko.observable();
function validate(newValue) {
var isInvalid = isNaN(HMS2Sec(newValue));
observable.hasError(isInvalid ? true : false);
observable.errorMessage(isInvalid ? errorMessage : null);
}
//initial validation
validate(observable());
//validate whenever the value changes
observable.subscribe(validate);
//return the original observable
return observable;
};
this.startTime = 120; // Start at 120 seconds
this.duration = ko.observable(0);
this.stopTimeHMS = ko.observable("00:00:00").HMSValidate("HH:MM:SS please");
But how do I get them working together? If I add the HMSValidate to the computed in the first block it doesn't work because by the time HMSValidate's validate function gets the value it's already been changed.
I have made it work in the first block by adding another observable that keeps track of the "raw" value passed into the computed and then adding another computed that uses that value to decide if it's an error state or not, but that doesn't feel very elegant.
Is there a better way?
http://jsfiddle.net/cygnl7/njNaS/2/
I came back to this after a week of wrapping up issues that I didn't have a workaround for (code cleanup time!), and this is what I have.
I ended up with the idea that I mentioned in the end of the question, but encapsulating it in the fn itself.
ko.subscribable.fn.hmsValidate = function (errorMessage) {
var origObservable = this;
var rawValue = ko.observable(origObservable()); // Used for error checking without changing our main observable.
if (!origObservable.hmsFormatValidator) {
// Handy place to store the validator observable
origObservable.hmsFormatValidator = ko.computed({
read: function () {
// Something else could have updated our observable, so keep our rawValue in sync.
rawValue(origObservable());
return origObservable();
},
write: function (newValue) {
rawValue(newValue);
if (newValue != origObservable() && !isNaN(HMS2Sec(newValue))) {
origObservable(newValue);
}
}
});
origObservable.hmsFormatValidator.hasError = ko.computed(function () {
return isNaN(HMS2Sec(rawValue()));
}, this);
origObservable.hmsFormatValidator.errorMessage = ko.computed(function () {
return errorMessage;
}, this);
}
return origObservable.hmsFormatValidator;
};
What this does is creates another computed observable that acts as a front/filter to the original observable. That observable has some other sub-observables, hasError and errorMessage, attached to it for the error states. The rawValue keeps track of the value as it was entered so that we can detect whether it was a good value or not. This handles the validation half of my requirements.
As for making two values dependent on each other, the original code in my question works. To make it validated, I add hmsValidate to it, like so:
this.stopTimeFormatted = ko.computed({
read: function () {
return Sec2HMS(this.startTime + parseInt(this.duration()), true);
},
write: function (value) {
this.duration(HMS2Sec(value) - this.startTime);
},
owner: this
}).hmsValidate("HH:MM:SS please");
See it in action here: http://jsfiddle.net/cygnl7/tNV5S/1/
It's worth noting that the validation inside of write is no longer necessary since the value will only ever be written by hmsValidate if it validated properly.
This still feels a little inelegant to me since I'm checking isNaN a couple of times and having to track the original value (especially in the read()), so if someone comes up with another way to do this, I'm all ears.
I have a javascript plugin for a special image scroller. The scroller contains a bunch of timeout methods and a lot of variables with values set from those timeouts.
Everything works perfectly, but for the site I am working on it is required that the pages are loaded dynamically. The problem with this is when i for instance change the language on the site this is made by jquery load function meaning the content is dynamically loaded onto the site - AND the image slider aswell.
NOW here is the big problem! When I load the image slider for the second time dynamically all my previous values remains as well as the timers and everything else. Is there any way to clear everything in the javascript plugin as if it where like a page reload?
I have tried a lot of stuff so far so a little help would be much appreciated!
Thanks a lot!
You might want something like that to reload scripts:
<script class="persistent" type="text/javascript">
function reloadScripts()
{ [].forEach.call(document.querySelectorAll('script:not(.persistent)'), function(oldScript)
{
var newScript = document.createElement('script');
newScript.text = oldScript.text;
for(var i=0; i<oldScript.attributes.length; i++)
newScript.setAttribute(oldScript.attributes[i].name, oldScript.attributes[i].value);
oldScript.parentElement.replaceChild(newScript, oldScript);
});
}
// test
setInterval(reloadScripts, 5000);
</script>
As far as I know, there's no other way to reset a script than completely remove the old one and create another one with the same attributes and content. Not even clone the node would reset the script, at least in Firefox.
You said you want to reset timers. Do you mean clearTimeout() and clearInterval()? The methods Window.prototype.setTimeout() and Window.prototype.setInterval() both return an ID wich is to pass to a subsequent call of clearTimeout(). Unfortunately there is no builtin to clear any active timer.
I've wrote some code to register all timer IDs. The simple TODO-task to implement a wrapper callback for setTimeout is open yet. The functionality isn't faulty, but excessive calls to setTimeout could mess up the array.
Be aware that extending prototypes of host objects can cause undefined behavior since exposing host prototypes and internal behavior is not part of specification of W3C. Browsers could change this future. The alternative is to put the code directly into window object, however, then it's not absolutely sure that other scripts will call this modified methods. Both decisions are not an optimal choice.
(function()
{ // missing in older browsers, e.g. IE<9
if(!Array.prototype.indexOf)
Object.defineProperty(Array.prototype, 'indexOf', {value: function(needle, fromIndex)
{ // TODO: assert fromIndex undefined or integer >-1
for(var i=fromIndex || 0; i < this.length && id !== window.setTimeout.allIds[i];) i++;
return i < this.length ? i : -1;
}});
if(!Array.prototype.remove)
Object.defineProperty(Array.prototype, 'remove', { value: function(needle)
{ var i = this.indexOf(needle);
return -1 === i ? void(0) : this.splice(i, 1)[0];
}});
// Warning: Extensions to prototypes of host objects like Window can cause errors
// since the expose and behavior of host prototypes are not obligatory in
// W3C specs.
// You can extend a specific window/frame itself, however, other scripts
// could get around when they call window.prototype's methods directly.
try
{
var
oldST = setTimeout,
oldSI = setInterval,
oldCT = clearTimeout,
oldCI = clearInterval
;
Object.defineProperties(Window.prototype,
{
// TODO: write a wrapper that removes the ID from the list when callback is executed
'setTimeout':
{ value: function(callback, delay)
{
return window.setTimeout.allIds[window.setTimeout.allIds.length]
= window.setTimeout.oldFunction.call(this, callback, delay);
}
},
'setInterval':
{ value: function(callback, interval)
{
return window.setInterval.allIds[this.setInterval.allIds.length]
= window.setInterval.oldFunction.call(this, callback, interval);
}
},
'clearTimeout':
{ value: function(id)
{ debugger;
window.clearTimeout.oldFunction.call(this, id);
window.setTimeout.allIds.remove(id);
}
},
'clearInterval':
{ value: function(id)
{
window.clearInterval.oldFunction.call(this, id);
window.setInterval.allIds.remove(id);
}
},
'clearTimeoutAll' : { value: function() { while(this.setTimeout .allIds.length) this.clearTimeout (this.setTimeout .allIds[0]); } },
'clearIntervalAll': { value: function() { while(this.setInterval.allIds.length) this.clearInterval(this.setInterval.allIds[0]); } },
'clearAllTimers' : { value: function() { this.clearIntervalAll(); this.clearTimeoutAll(); } }
});
window.setTimeout .allIds = [];
window.setInterval .allIds = [];
window.setTimeout .oldFunction = oldST;
window.setInterval .oldFunction = oldSI;
window.clearTimeout .oldFunction = oldCT;
window.clearInterval.oldFunction = oldCI;
}
catch(e){ console.log('Something went wrong while extending host object Window.prototype.\n', e); }
})();
This puts a wrapper method around each of the native methods. It will call the native functions and track the returned IDs in an array in the Function objects of the methods. Remember to implement the TODOs.