In trying to learn more about JavaScript patterns I created the following 2 "Meters" based on an example I found. Is Meter1 better because it uses the Observable Property (or so I think) pattern? Would this pattern be used real-world or not really because of all the frameworks available?
//Meter1 - Observable Property Pattern
var Meter1 = function (count) {
var countChanging = [],
countChanged = [];
this.count = function (val) {
if (val !== undefined && val !== count) {
for (var i = 0; i < countChanging.length; i++) {
if (!countChanging[i](this, val)) {
return count;
}
}
count = val;
for (var i = 0; i < countChanged.length; i++) {
countChanged[i](this);
}
}
return count;
};
this.increment = function () {
return count = count + 1;
}
this.onCountChanging = function (callback) {
countChanging.push(callback);
};
this.onCountChanged = function (callback) {
countChanged.push(callback);
};
};
var meter = new Meter1(5);
var btnClick = document.getElementById('btnClick');
btnClick.addEventListener('click', function () {
meter.count(meter.count() + 1);
}, false);
meter.onCountChanging(function (b, count) {
if (count > 10) {
document.getElementById('numClicks').innerHTML = "Enough already!!!!!";
return false;
}
return true;
});
meter.onCountChanged(function () {
document.getElementById('numClicks').innerHTML = "Test " + meter.count();
});
//Meter2 - Does the same thing, is Observable Property pattern better?
var Meter2 = function (count) {
this.count = 0;
};
var meter2 = new Meter2(5);
var btnClick2 = document.getElementById('btnClick2');
btnClick2.addEventListener('click', function () {
meter2.count = meter2.count + 1;
if (meter2.count > 10) {
document.getElementById('numClicks2').innerHTML = "Enough already!!!!!";
} else {
document.getElementById('numClicks2').innerHTML = "Test " + meter2.count;
}
}, false);
<body>
<div id="numClicks">Test</div>
<div id="numClicks2">Test</div>
<button id="btnClick">Click - Meter</button>
<button id="btnClick2">Click - Meter 2</button>
</body>
</html>
<script src="../js/generalTesting.js"></script>
Related
Can you please help me with how to use this function in Postman test script section?
() => {
var sleep = (sleepDuration) => {
var startTime = new Date().getTime();
while (new Date().getTime() - startTime < sleepDuration) {}
}
var sleepByAsyncDelayTime = () => {
var sleepDuration = postman.getEnvironmentVariable('asyncDelayTime') || 0;
sleep(sleepDuration);
}
var retryOnFailure = (predicate, numberOfRetrys, sleepDuration, reRouteRequestName, postmanAssertions) => {
var retryCountPerReq_key = request.name + '_retry_count';
var retryCountPerReq = pm.environment.get(retryCountPerReq_key) || 0;
var reflowCountPerReq_key = request.name + '_reflow_count';
var reflowCountPerReq = pm.environment.get(reflowCountPerReq_key) || 0;
var totalReflowCount_key = 'totalReflowCount';
var totalReflowCount = pm.environment.get(totalReflowCount_key) || 0;
var maxReflowCounter = postman.getEnvironmentVariable('maxReflowCounter') || 0;
var maxReflowCounterPerReq = postman.getEnvironmentVariable('maxReflowCounterPerReq') || 0;
function clearAndExit() {
pm.environment.unset(retryCountPerReq_key);
pm.environment.unset(reflowCountPerReq_key);
postmanAssertions();
}
function retry() {
sleep(sleepDuration);
pm.environment.set(retryCountPerReq_key, ++retryCountPerReq);
postman.setNextRequest(request.name);
}
function reFlow() {
if (totalReflowCount < maxReflowCounter && reflowCountPerReq < maxReflowCounterPerReq) {
pm.environment.unset(retryCountPerReq_key);
pm.environment.set(totalReflowCount_key, ++totalReflowCount);
pm.environment.set(reflowCountPerReq_key, ++reflowCountPerReq);
postman.setNextRequest(reRouteRequestName);
} else clearAndExit();
}
if (predicate()) clearAndExit();
else if (retryCountPerReq < numberOfRetrys) retry();
else if (reRouteRequestName != '') reFlow();
else clearAndExit();
}
return {
common: {
sleepByAsyncDelayTime,
sleep,
retryOnFailure
}
};
}
I have followed this and still unable to make assertion with retries.
I want to set this as a function and run test cases on the collection runner.
Postman / Newman retry in case of failure
You could also do it like this:
var expectedHttpStatus = 200;
var maxNumberOfTries = 3;
var sleepBetweenTries = 5000;
if (!pm.environment.get("collection_tries")) {
pm.environment.set("collection_tries", 1);
}
if ((pm.response.code != expectedHttpStatus) && (pm.environment.get("collection_tries") < maxNumberOfTries)) {
var tries = parseInt(pm.environment.get("collection_tries"), 10);
pm.environment.set("collection_tries", tries + 1);
setTimeout(function() {}, sleepBetweenTries);
postman.setNextRequest(request.name);
} else {
pm.environment.unset("collection_tries");
pm.test("Status code is " + expectedHttpStatus, function () {
pm.response.to.have.status(expectedHttpStatus);
});
// more tests here...
}
How can i send parameter this to function.
Above options work in constructor :
selectors[i].onblur = this.validation;
But if in function Valid i call the selectors[i].validation, above solution will not working. Does Somebody know, how to call selectors[i].validation with parameter this??
For any help, i will be very grateful.
link to demo:
http://codepen.io/anon/pen/YqryVr
My js classes:
var Validator = (function () {
var errorClassName = "error";
var selectors;
var regexMap;
function Validator(id, regexObject) {
if (id === void 0) { id = "form"; }
regexMap = regexObject.getMap();
selectors = document.getElementById(id).elements;
for (i = 0; i < selectors.length; ++i) {
selectors[i].onblur = this.validation;
}
};
Validator.prototype.setErrorClassName = function (className) {
errorClassName = className;
};
Validator.prototype.addClass = function (selector) {
if(selector.className.indexOf(errorClassName) < 1)
selector.className += " " + errorClassName;
};
Validator.prototype.removeClass = function (selector) {
selector.className = selector.className.replace(errorClassName, '');
};
Validator.prototype.validation = function () {
alert('this.type: ' + this.type);
switch(this.type) {
case 'textarea':
case 'text':
if(this.dataset.regex in regexMap) this.dataset.regex = regexMap[this.dataset.regex];
var pattern = new RegExp(this.dataset.regex);
if(this.value.length !== 0 && pattern.test(this.value)) {
Validator.prototype.removeClass(this);
return true;
} else {
Validator.prototype.addClass(this);
return false;
}
break;
case 'select-one':
if(this.value.length === 0) {
Validator.prototype.addClass(this);
return false;
} else {
Validator.prototype.removeClass(this);
return true;
}
break;
}
return true;
};
Validator.prototype.valid = function () {
for (i = 0; i < selectors.length; ++i) {
selectors[i].validation;
}
return true;
};
return Validator;
}());
var SelectorAttribute = (function () {
function SelectorAttribute(name, regex) {
this.name = name;
this.regex = regex;
}
SelectorAttribute.prototype.toString = function () {
return "name: " + this.name + ", regex = " + this.regex;
};
return SelectorAttribute;
}());
var StandardRegexPatterns = (function () {
var map = {};
function StandardRegexPatterns() {
map['zip-code-poland'] = '^[0-9]{2}-[0-9]{3}$';
map['phone-number-poland'] = '^[0-9]{9}$';
map['digits'] = '^[0-9]+$';
map['alpha'] = '^[a-zA-z]+$';
map['email'] = '^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*#([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+)*\.(aero|arpa|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro|travel|mobi|[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?';
map['login'] = '^[a-z0-9_-\.]{3,21}$';
map['ip-address'] = '^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$';
map['url-address'] = '^((http[s]?|ftp):\/)?\/?([^:\/\s]+)((\/\w+)*\/)([\w\-\.]+[^#?\s]+)(.*)?(#[\w\-]+)?$';
}
StandardRegexPatterns.prototype.getMap = function () {
return map;
};
return StandardRegexPatterns;
}());
$( document ).ready(function() {
var validator = new Validator('form', new StandardRegexPatterns());
validator.setErrorClassName("error");
//var pattern = new StandardRegexPatterns();
// alert(Object.keys(pattern.getMap()));
$("button").on('click', function(){
alert(validator.valid());
});
});
You can use the following:
functionname.apply(this, [arguments]);
or
functionname.call(this, argument1, argument2);
if you don't have arguments you can just omit them.
I usually just do this:
funcitonname.apply(this, Arguments);
if I'm calling this method from within a function already so I can carry on the arguments to the functionname().
Learn more about apply
Learn more about call
This is a program to find the nth fibonacci number.
var fib = (function() {
var save = [];
var i = 0;
return {
"getNum": function(input) {
this.input = input;
if (input === 0) {
console.log("Invalid input");
}
save[i] = i;
save[i + 1] = i + 1;
save[i + 2] = i + 1;
i = 2;
for (i >= 2; i < input; i = i + 1) {
save[i + 1] = save[i] + save[i - 1];
}
console.log(save[i - 1]);
}
}
}());
fib.getNum(4);
My question is when I implement this problem in the following way, it doesn't work. I understand this is because I am not calling the sub-functions and only calling the main function. Is there a better pattern we can use that will keep the code organised and we won't have to make calls to so many functions?
var fib = (function() {
var save = [];
var i = 0;
return {
"getNum": function(input) {
this.input = input;
function valid() {
if (input === 0) {
console.log("Invalid input");
}
}
function config() {
save[i] = i;
save[i + 1] = i + 1;
save[i + 2] = i + 1;
i = 2;
}
function nthNum() {
for (i >= 2; i < input; i = i + 1) {
save[i + 1] = save[i] + save[i - 1];
}
console.log(save[i - 1]);
}
}
}
}());
fib.getNum(4);
You can think of using closure to create private and public functions.If you see the below code only _getNum function is exposed.
var fib = (function() {
var save = [];
save[0] = 0;
save[1] = 1;
var i = 0;
//This will validate the number
// This function can be avoided and make _getNum do the same
function _valid(input){
console.log("Method Executing:_valid");
input === 0 ? console.log('Invalid Input') : _nthNum(input);
}
// Will calualte the series.
// This is a private function
function _nthNum(input) {
console.log('Method Executing:_nthNum');
for (i = 2; i<=input; i++) {
save[i] = save[i-2] + save[i - 1];
}
console.log(save.pop());
}
// Private Function
function _getNum(input){
console.log("Method Executing :_getNum" ,input);
_valid(input);
}
//Expose the private function
return {
getNum :_getNum // Expose _getNum
}
}());
fib.getNum(0);
fib.getNum(4);
fib.getNum(7);
WORKING COPY
My suggestion:
var Fibonacci = (function() {
var _Fibonacci = {
// set initial values
result: [0, 1, 1],
input: 0,
// main function
find: function (number) {
this.input = number;
if (this.isValid()) {
this.calculate();
return this.result.pop();
}
return 'Invalid input';
},
// sub functions
isValid: function () {
return this.input != 0
},
calculate: function () {
for (var i=2; i<this.input; i++) { // fix your code here
this.result[i+1] = this.result[i] + this.result[i-1];
}
}
};
// return the main function
return _Fibonacci.find.bind(_Fibonacci);
}());
console.log(
Fibonacci(0),
Fibonacci(4),
Fibonacci(6)
);
I've tried this a thousand different ways in a thousand different times and my JS code won't come out the way I want it. When I run it in the Mozilla scratchpad, I get "userHand is undefined" and the second printHand shows as undefined, too. Could someone show me where are the errors in my blackjack game?
function Card (s, n) {
var suit = s;
var number = n;
this.getNumber = function () {
return number;
};
this.getSuit = function () {
return suit;
};
this.getValue = function () {
if (number > 10) {
return 10;
} else if (number === 1) {
return 11;
} else {
return number;
}
};
}
var cardNames = {1:"Ace", 2:"2", 3:"3", 4:"4", 5:"5", 6:"6", 7:"7", 8:"8", 9:"9", 10:"10", 11:"Joker", 12:"Queen", 13:"King"};
var suitNames = {1:"Clubs", 2:"Diamonds", 3:"Hearts", 4:"Spades"};
var deal = function () {
var s = Math.floor(Math.random() * 4 + 1);
var n = Math.floor(Math.random() * 13 + 1);
return new Card(s, n);
};
function Hand(){
var cards = [];
cards.push(deal());
cards.push(deal());
this.getHand = function () {
return cards;
};
this.score = function () {
var score;
for (i = 0; i < cards.length; i++) {
score = score + cards[i].getValue();
}
for (i = 0; i < cards.length; i++) {
if (score > 21 && cards[i].getValue() === 11) {
score = score - 10;
}
} return score;
};
this.printHand = function () {
for (i = 0; i < cards.length; i++) {
var hand;
if (i === 0) {
hand = cardNames[cards[i].getNumber()] + " of " + suitNames[cards[i].getSuit()];
} else {
hand = hand + " and a " + cardNames[cards[i].getNumber()] + " of " + suitNames[cards[i].getSuit()];
}
} alert(hand);
};
this.hitMe = function () {
cards.push(deal());
};
}
var playAsDealer = function () {
var playDealer = new Hand();
while (playDealer.score() < 17) {
playDealer.hitMe();
}
this.printHand = function () {
return playDealer.printHand();
};
this.score = function () {
return playDealer.score();
};
};
var playAsUser = function () {
var playUser = new Hand();
this.printHand = function () {
return playUser.printHand();
};
this.score = function () {
return playUser.score();
};
var decision = confirm("Your hand is " + playUser.printHand() + ". Click OK to hit or Cancel to stand");
for (i = 0; decision !== false; i++) {
playUser.hitMe();
decision = confirm("Your hand is " + playUser.printHand() + ". Click OK to hit or Cancel to stand");
}
};
var declareWinner = function (userHand, dealerHand) {
if ((userHand.score < dealerHand.score) || userHand.score > 21) {
return "You lose.";
} else if (userHand.score > dealerHand.score) {
return "You win.";
} else {
return "You tied.";
}
};
var playGame = function () {
var user = playAsUser();
var dealer = playAsDealer();
declareWinner(user, dealer);
console.log("User got " + user.printHand());
console.log("Dealer got " + dealer.printHand());
};
playGame();
You aren't returning nothing on printHand()
I just added the return statement and worked. See this fiddle
this.printHand = function () {
for (i = 0; i < cards.length; i++) {
var hand;
if (i === 0) {
hand = cardNames[cards[i].getNumber()] + " of " + suitNames[cards[i].getSuit()];
} else {
hand = hand + " and a " + cardNames[cards[i].getNumber()] + " of " + suitNames[cards[i].getSuit()];
}
}
//alert(hand); //remove this alert
return hand; // <----- solution
};
I build a prototype that handle pages, I successfully add (push), but can get the data, I failed:
var foundImageIndex = Pages.indexFirst(function (item) { if (item.PageID == PageID) return true; });
Here the javascript page handler:
var Pages = new Array();
PageContainer = function () //constructor for the proxy
{
// this._baseURL = url;
};
PageContainer.prototype =
{
AddPage: function (data) {
if (data == null) return;
Pages.push({ PageID: data.PageID, SegmentID: data.SegmentID });
},
GetPage: function (PageID) {
alert('getPage('+PageID+')=' + JSON.stringify(Pages));
var foundImageIndex = Pages.indexFirst(function (item) { if (item.PageID == PageID) return true; });
var dt = { PageID: Pages[foundImageIndex].PageID, SegmentID: Pages[foundImageIndex].SegmentID };
return dt;
}
};
I call from other js as following:
var gPageContainer = new PageContainer();
for (var i = 0; i < SegStruct.SegmentsCount; i++) {
var segRClass = //get from webservice
gPageContainer.AddPage({ PageID: i, SegmentID: segRClass.SegmentID });
}
I trying to call: gPageContainer.GetPage(1); but it failed in GetPage: function (PageID) it returns -1 in:
var foundImageIndex = Pages.indexFirst(function (item) { if (item.PageID == PageID) return true; });
foundImageIndex always -1
why?
Simply add the following before the constructor:
if (typeof Array.prototype.indexFirst == 'undefined') {
Array.prototype.indexFirst = function (validator) {
for (var i = 0; i <= this.length - 1; i++) {
if (validator(this[i])) {
return i;
}
}
return -1;
};
}