Custom Closure Function Undefined JS Browser - javascript

I have a very simple html page where I put this script at the end:
<?php echo $this->Html->script(['studiomain.js']); ?>
</html>
The script contains an IIF in JS:
window.studiomain = window.studiomain || (function ($) {
let _dataTable = '';
let _modalTemplates = {};
let _webroot = 'studioasq';
function setDataTable (t, options={}) {
_dataTable = $(t);
if (typeof $(t).DataTable == 'function') {
options.language = {
"url": "/" + _webroot + "/js/datatable/i18n/Italian.json"
}
$(t).DataTable(options);
}
}
function setModal(key='',template='') {
_modalTemplates[key] = template;
}
function renderModal(key,data={}) {
if (_modalTemplates[key] !== undefined) {
let copy = _modalTemplates[key];
Object.keys(data).forEach((key) => {
copy.replace(new RegExp("{{" + value + "}}","g"),data[key]);
})
}
return $('#'+key);
}
return {
setDataTable,
setModal,
renderModal
}
})($);
But when the page finishes loading, I have no studiomain in window:
window.studiomain => undefined.
I think the problem is the renderModal function: If I delete it all is fine.
What am I missing?
**** UPDATE ****
Following suggestions, I think the problem is in the order of loading scripts and passing the reference to JQuery.
I discovered also that passing (jQuery) and NOT ($) to the IIF works.

I guess you are trying to achieve modular pattern.
In your code, you'll need to return every thing inside a function, otherwise every code without return will be in private state.
Fix of your code, you need to return window.studiomain as a parameter, you code will work, $ is not defined therefore it's not storing inside window object
window.studiomain = window.studiomain || (function($) {
let _dataTable = '';
let _modalTemplates = {};
let _webroot = 'studioasq';
function setDataTable(t, options = {}) {
_dataTable = $(t);
if (typeof $(t).DataTable == 'function') {
options.language = {
"url": "/" + _webroot + "/js/datatable/i18n/Italian.json"
}
$(t).DataTable(options);
}
}
function setModal(key = '', template = '') {
_modalTemplates[key] = template;
}
function renderModal(key, data = {}) {
if (_modalTemplates[key] !== undefined) {
let copy = _modalTemplates[key];
Object.keys(data).forEach((key) => {
copy.replace(new RegExp("{{" + value + "}}", "g"), data[key]);
})
}
return $('#' + key);
}
return {
setDataTable,
setModal,
renderModal
}
})(window.studiomain);
console.log(studiomain);

Related

How to access object array using javascript with variable

var dict = {
"configMigratedTo": {
"message": "Migrated configuration to configurator: $1"
}
}
var parametersForTranslation = {};
function __tr(src, params) {
parametersForTranslation[src] = params;
return buildMessage(src);
}
function buildMessage(src){
var message=dict[src] ? dict[src].message : src
console.log(message);
var messageArray = message.split("$");
var output = "";
messageArray.forEach(function(elem, index){
if(index === 0){
output += elem;
}else{
// get variable and index
var paramIndex = configMigratedTo.substring(0, 1);
var paramValue = parametersForTranslation[src][paramIndex-1];
output += paramValue;
output += configMigratedTo.substring(1);
}
});
return output;
}
__tr("configMigratedTo", [2]);
console.log(buildMessage("configMigratedTo"));
i want get result like __tr("configMigratedTo", [2]);
then it will give me
Migrated configuration to configurator: 2
i do not know where is wrong in my code
Try this one. Hope it helps!
var dict = {
"configMigratedTo": {
"message": "Migrated configuration to configurator: $1"
}
}
function __tr(src, params)
{
for (var key in dict)
{
if (key === src)
{
var message = dict[key].message;
return message.substring(0, message.length - 2) + params[0];
}
}
return;
}
console.log(__tr("configMigratedTo", [2]))
https://jsfiddle.net/eLd9u2pq/
Would that be enought?
var dict = {
"configMigratedTo": {
"message": "Migrated configuration to configurator: "
}
}
function buildMessage(src,param){
var output = dict[src].message + param;
return output;
}
console.log(buildMessage("configMigratedTo",2));
You are overcomplicating this, it's much easier using a regex and passing a function as replacer
var dict = {
"configMigratedTo": {
"message": "Migrated configuration to configurator: $1"
}
}
function __tr(src, params) {
if (! dict[src]) return src;
if (! /\$0/.test(dict[src].message)) params.unshift('');
return dict[src].message.replace(/\$(\d)+/g, (orig, match) => params[match] || orig);
}
console.log(__tr("configMigratedTo", [2]));

Knockotjs Validation. Passing function gives undefined, because of property order inside VM

validation works fine if validation properties are placed after "HasError" property in VM.
In the case that the property placed before HasError I will get "parameters.hasError" as undefined. I think it's because the property "HasError" is not defined to that time.
Is there any solution without changing the order of the properties inside VM to make it work.
Thanks!
self._BusTypeDefault = function(param) {
var ret = param.BusType;
if(typeof(ret)==='undefined') {
ret = '';
}
else if(ko.isObservable(ret)) {
ret = ret.peek();
}
return ret;
};
self.BusType = ko.observable(self._BusTypeDefault(init)).extend({maxLength: {message: $Resources.PCIBUSError(), maxFieldLength: 255,hasError: self.HasError }});
self._HasErrorDefault = function(param) {
var ret = param.HasError;
if(typeof(ret)==='undefined') {
ret = false;
}
else if(ko.isObservable(ret)) {
ret = ret.peek();
}
return ret;
};
self.HasError = ko.observable(self._HasErrorDefault(init)).extend({errorAggregation: {}});
ko.extenders.maxLength = function (target, parameters) {
//add some sub-observables to our observable
target.hasMaxLengthError = ko.observable();
target.validationMessageMaxError = ko.observable();
//define a function to do validation
function validate(newValue) {
var preValue = target.hasMaxLengthError();
if (newValue.length >= parameters.maxFieldLength) {
target.hasMaxLengthError(true);
target.validationMessageMaxError(parameters.message || "This field is required");
}
else {
target.hasMaxLengthError(false);
target.validationMessageMaxError("");
}
if (parameters.hasError != null && target.hasMaxLengthError() !== preValue && typeof preValue !== 'undefined') {
parameters.hasError(target.hasMaxLengthError());
}
}
//initial validation
validate(target());
//validate whenever the value changes
target.subscribe(validate);
//return the original observable
return target;
};
You can use a function to delay the interpretation of hasError:
this.myObservable = ko.observable(1).extend({ myExtender : { hasError: function () { return self.hasError } } });
Then in the extender you'll need to call the function to actually get the observable behind:
ko.extenders.myExtender = function (target, params) {
function validate(newValue) {
alert("New Value: " + newValue + " ; Has Error: " + params.hasError()());
}
target.subscribe(validate);
}
See this example: http://jsfiddle.net/7ywLN/

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

what's a proper way to check for null/empty string in js before including to params?

I am building a querystring and want to exclude keys if vals are empty, what's a proper way?
setQueryString: function () {
var keyword = $('#keyword').val();
//how to exclude it if keyword is empty?
var params = {
"keyword": $.trim(keyword)
};
return params;
}
take into account, that I will have 20+ inputs like keyword..trying to avoid lots of IF statements
If you have multiple params and you don't want lots of if statements:
setQueryString: function () {
var params = {
'param1': $.trim($('#param1').val()),
'param2': $.trim($('#param2').val())
}
for (p in params) {
if (params.p == null || params.p == '') {
delete params.p;
}
}
return params;
}
Don't set it if it's empty is all:
var keyword = $.trim($('#keyword').val());
var params = {};
if(keyword) {
params.keyword = keyword;
}
return params;
(edit)
If you have lots of things to check, consider using either a loop:
var items = {
keyword: $.trim($('#keyword').val())
// etc.
};
var params = {};
for(var x in items) {
if(items.hasOwnProperty(x) && items[x]) {
params[x] = items[x];
}
}
return params;
or a function of some kind, for example:
var params = {};
function check(name) {
var value = $.trim($('#' + name).val());
if(value) {
params[name] = value;
}
}
check('keyword');
// etc.
return params;
As an empty string is a falsy value in JavaScript you can simpley check if val() is true:
setQueryString: function () {
var keyword = $('#keyword').val();
if(keyword){
var params = {
"keyword": $.trim(keyword)
};
return params;
}
}
Try something like:
setQueryString: function () {
var keyword = $.trim($('#keyword').val());
var params = {};
if(keyword !== undefined && keyword !== '') {
params.keyword = keyword;
}
return params;
}
I believe you need extend: http://api.jquery.com/jQuery.extend/

how to get the querystring from a parent page?

i am using an iframe ipage in my parentpage. I would like to get the querystring in javascript of the parentpage?
I suggest to you to use my favourite function:
function getQueryString() {
var queryStringKeyValue = window.parent.location.search.replace('?', '').split('&');
var qsJsonObject = {};
if (queryStringKeyValue != '') {
for (i = 0; i < queryStringKeyValue.length; i++) {
qsJsonObject[queryStringKeyValue[i].split('=')[0]] = queryStringKeyValue[i].split('=')[1];
}
}
return qsJsonObject;
}
Just call it from the child window like this and act with the query string as an object.
For example if you have the query string ?name=stack and you want to get it, try:
getQueryString().name
This will return stack.
nice answer from #Marawan. - if it helps anyone...
I extended this to choose the target as a parameter (self / parent)
function getQueryString(target) {
if ( target == 'parent' ) {
var queryStringKeyValue = window.parent.location.search.replace('?', '').split('&');
}
else {
var queryStringKeyValue = window.location.search.replace('?', '').split('&');
}
var qsJsonObject = {};
if (queryStringKeyValue != '') {
for (i = 0; i < queryStringKeyValue.length; i++) {
qsJsonObject[queryStringKeyValue[i].split('=')[0]] = queryStringKeyValue[i].split('=')[1];
}
}
return qsJsonObject;
}
eg.
getQueryString('parent').id; // get iframe parent url ?id=foo
getQueryString().id; // get this url ?id=foo
ES6 implementation:
export const getQueryParameters = () => {
const queryStringKeyValue = window.parent.location.search.replace('?', '').split('&');
return queryStringKeyValue.reduce((acc, curr) => {
const [key,value] = curr.split('=')
return {
...acc,
[key]: value
}
}, {})
}
Usage:
getQueryParameters().name

Categories