Send object this to functions that take No-arguments - javascript

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

Related

toString method on Linked List implementation not working in js

I'm working through Cracking the Coding Interview and I thought I'd implement all the data structures in JS 5. Can anyone explain to me why my toString method isn't working?
Thanks!
function Node(data) {
this.next = null;
this.data = data;
}
Node.prototype.appendToTail = function(data) {
var end = new Node(data);
var n = this;
while (n.next != null) {
n = n.next;
}
n.next = end;
}
Node.prototype.toString = function(head) {
console.log(head)
if (head == null) {
return ""
} else {
return head.data.toString() + "-> " + head.next.toString();
}
}
var ll = new Node(1);
ll.appendToTail(3);
ll.appendToTail(4);
console.log(ll.toString())
function Node(data) {
this.next = null;
this.data = data;
}
Node.prototype.appendToTail = function(data) {
var end = new Node(data);
var n = this;
while (n.next != null) {
n = n.next;
}
n.next = end;
};
Node.prototype.toString = function() {
var returnValue = String(this.data);
if (this.next) {
returnValue = returnValue + "-> " + String(this.next);
}
return returnValue;
};
var ll = new Node(1);
ll.appendToTail(3);
ll.appendToTail(4);
console.log(String(ll))
or avoid this kind of problems completly and do not use prototype, class, this, call, etc
Your toString function takes an argument, but you're not passing it when you call toString.
If you want to access the node, you should use this, instead of passing in a value
Node.prototype.toString = function() {
var result = this.data.toString();
if (this.next) {
result += "-> " + this.next.toString();
}
return result;
}

How to take the result of one script and feed it into another?

I'm in way over my head here and need some help to understand what I'm looking at please! (Very new to Javascript!) Here is the situation as I understand it...
I have a script that is selecting a single line from a paragraph of text, and currently produces this alert, where '1' is the selected line:
alert(getLine("sourcePara", 1));
...Instead of triggering an alert I need this selected text to feed into this separate script which is sending data to another browser window. Presently it's taking a text field from a form with the id 'STOCK1', but that can be replaced:
function sendLog() {
var msg = document.getElementById('STOCK1').value;
t.send('STK1', msg);
}
I'm totally confused as to what form this text data is taking on the way out of the first script and have no idea how to call it in as the source for the second... HELP!
All the thanks!
EDIT:
Here is the source code for the Local Connection element;
function LocalConnection(options) {
this.name = 'localconnection';
this.id = new Date().getTime();
this.useLocalStorage = false;
this.debug = false;
this._actions= [];
this.init = function(options) {
try {
localStorage.setItem(this.id, this.id);
localStorage.removeItem(this.id);
this.useLocalStorage = true;
} catch(e) {
this.useLocalStorage = false;
}
for (var o in options) {
this[o] = options[o];
}
this.clear();
}
this.listen = function() {
if (this.useLocalStorage) {
if (window.addEventListener) {
window.addEventListener('storage', this.bind(this, this._check), false);
} else {
window.attachEvent('onstorage', this.bind(this, this._check));
}
} else {
setInterval(this.bind(this, this._check), 100);
}
}
this.send = function(event) {
var args = Array.prototype.slice.call(arguments, 1);
return this._write(event, args);
}
this.addCallback = function(event, func, scope) {
if (scope == undefined) {
scope = this;
}
if (this._actions[event] == undefined) {
this._actions[event] = [];
}
this._actions[event].push({f: func, s: scope});
}
this.removeCallback = function(event) {
for (var e in this._actions) {
if (e == event) {
delete this._actions[e];
break;
}
}
}
this._check = function() {
var data = this._read();
if (data.length > 0) {
for (var e in data) {
this._receive(data[e].event, data[e].args);
}
}
}
this._receive = function(event, args) {
if (this._actions[event] != undefined) {
for (var func in this._actions[event]) {
if (this._actions[event].hasOwnProperty(func)) {
this.log('Triggering callback "'+event+'"', this._actions[event]);
var callback = this._actions[event][func];
callback.f.apply(callback.s, args);
}
}
}
};
this._write = function(event, args) {
var events = this._getEvents();
var evt = {
id: this.id,
event: event,
args: args
};
events.push(evt);
this.log('Sending event', evt);
if (this.useLocalStorage) {
localStorage.setItem(this.name, JSON.stringify(events));
} else {
document.cookie = this.name + '=' + JSON.stringify(events) + "; path=/";
}
return true;
}
this._read = function() {
var events = this._getEvents();
if (events == '') {
return false;
}
var ret = [];
for (var e in events) {
if (events[e].id != this.id) {
ret.push({
event: events[e].event,
args: events[e].args
});
events.splice(e, 1);
}
}
if (this.useLocalStorage) {
localStorage.setItem(this.name, JSON.stringify(events));
} else {
document.cookie = this.name + '=' + JSON.stringify(events) + "; path=/";
}
return ret;
}
this._getEvents = function() {
return this.useLocalStorage ? this._getLocalStorage() : this._getCookie();
}
this._getLocalStorage = function() {
var events = localStorage.getItem(this.name);
if (events == null) {
return [];
}
return JSON.parse(events);
}
this._getCookie = function() {
var ca = document.cookie.split(';');
var data;
for (var i=0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1, c.length);
}
if (c.indexOf(this.name+'=') == 0) {
data = c.substring(this.name.length+1, c.length);
break;
}
}
data = data || '[]';
return JSON.parse(data);
}
this.clear = function() {
if (this.useLocalStorage) {
localStorage.removeItem(this.name);
} else {
document.cookie = this.name + "=; path=/";
}
}
this.bind = function(scope, fn) {
return function () {
fn.apply(scope, arguments);
};
}
this.log = function() {
if (!this.debug) {
return;
}
if (console) {
console.log(Array.prototype.slice.call(arguments));
}
}
this.init(options);
}
If I understand what you are asking for correctly, then I think its a matter of changing your log function to the following:
function sendLog() {
t.send('STK1', getLine("sourcePara", 1));
}
This assumes that getLine is globally accessible.
Alternatively Another approach would be to allow for the sendLog function to take the message as a parameter. In which case, you would change your first script to be:
sendLog(getLine("sourcePara", 1));
And the modified sendLog function would look like this:
function sendLog(msg) {
t.send('STK1', msg);
}
LocalConnection.js should handle transferring the data between windows/tabs. Looks like an an iteresting project:
https://github.com/jeremyharris/LocalConnection.js

How to get dynamic HTML and Javascript values from a page using PhantomJS

How can I get the latest page data (HTML & Javascript varaibles) from PhantomJS
e.g page.refresh() or something?
I have an Interval, than checks a variable (on the page) every 200ms. However, this variable and the page content, isn't shown to have changed over time. (even though I know it has)
So I need an efficient way to check the value of a JS variable every 200ms or so,
then once I've discovered that variable has changed value, I want to request the latest page HTML.
How can I do this?
var Error = function (description) {
this.description = description;
return this;
};
var DTO = function (status, content, error) {
this.status = status;
this.content = content;
this.error = error;
return this;
};
function outputAndExit(dto) {
console.log(JSON.stringify(dto));
phantom.exit();
}
//For any uncaught exception, just log it out for .NET to capture
window.onerror = function (errorMsg, url, lineNumber) {
var description = 'window.onerror caught an error: ' +
'errorMsg: ' + errorMsg +
'url: ' + url +
'lineNumber: ' + lineNumber;
outputAndExit(new DTO(false, null, new Error(description)));
};
var GetDynamicPageResult__ = function () {
var obj = new GetDynamicPageResult();
obj.initialize();
return obj;
};
var GetDynamicPageResult = function () {
var self = this;
this.initialize = function () {
this.error = null;
this.isContentReadyForCrawler = false;
this.ticker = null;
this.tickerInterval = 150;
this.tickerElapsed = 0;
this.url = '';
this.loadDependencies();
this.processArgs();
this.openPage();
};
this.loadDependencies = function () {
this.system = require('system'),
this.page = require('webpage').create(),
this.page.injectJs('jquery-1.10.2.min');
this.fs = require('fs');
};
this.processArgs = function () {
if (this.system.args.length == 0) {
outputAndExit(new DTO(false, null, new Error('No arguments given')));
}
//system.args[0] Was the name of this script
this.url = this.system.args[1];
};
this.updateIsContentReadyForCrawler = function () {
var updateIsContentReadyForCrawler = self.page.evaluate(function () {
self.isContentReadyForCrawler = window.isContentReadyForCrawler;
});
};
this.openPage = function () {
self.page.open(this.url, function (status) { //NB: status = 'success' || 'fail'
if (status !== 'success') {
outputAndExit(new DTO(false, null, new Error('page.open received a non-success status')));
}
self.initTicker();
});
};
this.initTicker = function () {
this.ticker = setInterval(self.handleTick, self.tickerInterval);
};
this.handleTick = function () {
self.tickerElapsed += self.tickerInterval;
self.updateIsContentReadyForCrawler();
if (self.isContentReadyForCrawler) {
clearInterval(self.ticker);
var content = self.page.content;
self.finish(true, content, null);
} else {
var tooMuchTimeElapsed = self.tickerElapsed > 7000;
if (tooMuchTimeElapsed) {
clearInterval(self.ticker);
self.finish(false, null, new Error('Too much time elapsed'));
}
}
};
this.finish = function (status, content, error) {
content = content || '';
error = error || {};
outputAndExit(new DTO(status, content, error));
};
};
/**********************************************************************************/
/***************************** Helpers *****************************/
/**********************************************************************************/
var Utility__ = function () {
var obj = new Utility();
obj.initialize();
return obj;
};
var Utility = function () {
var self = this;
this.initialize = function () {
};
this.isEmpty = function (obj) {
var isEmpty = false;
(obj == undefined || obj == null) && (isEmpty = true);
return isEmpty;
};
this.isStringEmpty = function (str) {
var isEmpty = false;
isEmpty(str) && (isEmpty = true);
(isEmpty == false && $.trim(str) == '') && (isEmpty = true);
return isEmpty;
};
};
var getDynamicPageResult = new GetDynamicPageResult__();
I think you are almost there: you need to be using page.evaluate(), but currently only use it to get window.isContentReadyForCrawler. You need to use page.evaluate() to grab the latest HTML too.
I'm going to shamelessly paste in code from another answer (https://stackoverflow.com/a/12044474/841830):
var html = page.evaluate(function () {
var root = document.getElementsByTagName("html")[0];
var html = root ? root.outerHTML : document.body.innerHTML;
return html;
});

How this and $(this) end up being the same when extending jQuery?

I'm trying to work with a plugin which extends jQuery like so:
$.extend({
StatelessDeferred: function () {
var doneList = $.Callbacks("memory"),
promise = {
done: doneList.add,
// Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object
promise: function (obj) {
var i,
keys = ['done', 'promise'];
if (obj === undefined) {
obj = promise;
} else {
for (i = 0; i < keys.length; i += 1) {
obj[keys[i]] = promise[keys[i]];
}
}
return obj;
}
},
deferred = promise.promise({});
deferred.resolveWith = doneList.fireWith;
return deferred;
}
});
Problem is (and I'm not even sure it's caused here), after the callback loads, inside a done callback, both this and $(this) are the same, so I end up for example with: this === $(this) === $(document).
I'm not really sure I understand what's being extended. The plugin works fine with it except for the false assignment.
Question:
Could the above extension be causing this === $(this) === $(document)?
EDIT:
Full plugin (120lines):
"use strict";
(function (window, $) {
$.extend({
StatelessDeferred: function () {
var doneList = $.Callbacks("memory"),
promise = {
done: doneList.add,
// Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object
promise: function (obj) {
var i,
keys = ['done', 'promise'];
if (obj === undefined) {
obj = promise;
} else {
for (i = 0; i < keys.length; i += 1) {
obj[keys[i]] = promise[keys[i]];
}
}
return obj;
}
},
deferred = promise.promise({});
deferred.resolveWith = doneList.fireWith;
// All done!
return deferred;
}
});
var routes = [],
current_priority = 0,
methods = {
add: function (pattern, priority) {
var i = 0,
inserted = false,
length = routes.length,
dfr = $.StatelessDeferred(),
context = $(this),
escapepattern,
matchingpattern;
if (priority === undefined) {
priority = 0;
}
if (pattern !== undefined) {
// http://simonwillison.net/2006/Jan/20/escape/
escapepattern = pattern.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
matchingpattern = escapepattern
.replace(/<int:\w+>/g, "(\\d+)")
.replace(/<path:\w+>/g, "(.+)")
.replace(/<\w+>/g, "([^/]+)");
while (!inserted) {
if ((i === length) || (priority >= routes[i][2])) {
routes.splice(i, 0, [new RegExp('^' + matchingpattern + '$'), dfr, priority, context]);
inserted = true;
} else {
i += 1;
}
}
}
return dfr.promise();
},
go: function (path, min_priority) {
var dfr = $.Deferred(),
context = $(this),
result;
if (min_priority === undefined) {
min_priority = 0;
}
setTimeout(function () {
var i = 0,
found = false,
slice_index = -1,
slice_priority = -1;
for (i = 0; i < routes.length; i += 1) {
if (slice_priority !== routes[i][2]) {
slice_priority = routes[i][2];
slice_index = i;
}
if (routes[i][2] < min_priority) {
break;
} else if (routes[i][0].test(path)) {
result = routes[i][0].exec(path);
dfr = routes[i][1];
context = routes[i][3];
current_priority = routes[i][2];
found = true;
break;
}
}
if (i === routes.length) {
slice_index = i;
}
if (slice_index > -1) {
routes = routes.slice(slice_index);
}
if (found) {
dfr.resolveWith(
context,
result.slice(1)
);
} else {
dfr.rejectWith(context);
}
});
return dfr.promise();
},
};
$.routereset = function () {
routes = [];
current_priority = 0;
};
$.routepriority = function () {
return current_priority;
};
$.fn.route = function (method) {
var result;
if (methods.hasOwnProperty(method)) {
result = methods[method].apply(
this,
Array.prototype.slice.call(arguments, 1)
);
} else {
$.error('Method ' + method +
' does not exist on jQuery.route');
}
return result;
};
}(window, jQuery));
So I can use this as a router and set a route like so:
$(".element").add("route", "/foo/bar/<path:params>", 2).done(function(params){
// do something, for example
console.log(this);
console.log($(this));
console.log("which will be the same = $('.element'));
});
Hope it's more clear now.
Thanks for having a look.
From the documentation:
If only one argument is supplied to $.extend(), this means the target argument was omitted. In this case, the jQuery object itself is assumed to be the target.
Most cases, jQuery is attached to your document with : $(document).ready()
I think what's happening is jQuery object is wrapped onto the document. Then you merged it with $.extend(myObject). This returns a single object that is both jQuery object and myObject.

Javascript Array indexFirst

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;
};
}

Categories