What is new(this) mean in Javascript Function? - javascript

I found this code, to add before and after the ability to run a function, searched and don't know, what is new(self) mean there?
Function.prototype.before = function(fn) {
const self = this
return function() {
fn.apply(new(self), arguments)
return self.apply(new(self), arguments)
}
}
Function.prototype.after = function(fn) {
const self = this
return function() {
self.apply(new(self), arguments)
return fn.apply(new(self), arguments)
}
}
...
const validate = function(){
// ...
}
const formSubmit = function() {
// ...
ajax( 'http:// xxx.com/login', param )
}
submitBtn.onclick = function() {
formSubmit.before( validate )
}

Related

How to call function of JS added in header?

I have following JS which is added in header. I have button in page. I want to call "FulfillOrder" function of JS.
I don't know how to call it.
Can anybody please suggest me how can I call?
JS:
/// <reference path='../../../../ClientCommon/Sales_ClientCommon.d.ts' />
/// <reference path="../../../../../../TypeDefinitions/CRM/ClientUtility.d.ts" />
/// <reference path='../../../../CommandBarActions/SalesCommandBarActions.d.ts' />
var Sales;
(function (Sales) {
var SalesOrderRibbonActionsLibrary = (function () {
function SalesOrderRibbonActionsLibrary() {
var _this = this;
this.CloseOrFulfillOrder = function (closedState) {
var options = { height: 350, width: 475, position: 1 /* center */ };
options.width = 330;
options.height = 400;
var dialogParams = {};
dialogParams[Sales.MetadataDrivenDialogConstantsOrderClose.SalesId] = Xrm.Page.data.entity.getId();
dialogParams[Sales.MetadataDrivenDialogConstantsOrderClose.ClosedState] = closedState;
Xrm.Navigation.openDialog(Sales.DialogName.CloseOrder, options, dialogParams).then(_this.salesOrderDialogCloseCallback);
};
this.salesOrderDialogCloseCallback = function (response) {
var parameters = response.parameters;
var lastButtonClicked = parameters[Sales.MetadataDrivenDialogConstantsOrderClose.LastButtonClicked];
if (ClientUtility.DataUtil.isNullOrUndefined(lastButtonClicked) || lastButtonClicked.toString() !== ClientUtility.MetadataDrivenDialogConstants.DialogOkId) {
return;
}
var salesOrderId = parameters[Sales.MetadataDrivenDialogConstantsOrderClose.SalesId];
var date = new Date(parameters[Sales.MetadataDrivenDialogConstantsOrderClose.Date]);
var closedState = parseInt(parameters[Sales.MetadataDrivenDialogConstantsOrderClose.ClosedState]);
var reason = parseInt(parameters[Sales.MetadataDrivenDialogConstantsOrderClose.Reason]);
var description = null;
if (!ClientUtility.DataUtil.isNullOrUndefined(parameters[Sales.MetadataDrivenDialogConstantsOrderClose.Description])) {
description = parameters[Sales.MetadataDrivenDialogConstantsOrderClose.Description].toString();
}
if (!ClientUtility.DataUtil.isNullOrUndefined(date) && !ClientUtility.DataUtil.isNullOrUndefined(date)) {
_this.commandBarActions.PerformActionAfterCloseOrder(reason, date, description, closedState, salesOrderId);
}
};
/**
* Processes the sales order.
*/
this.ProcessOrder = function () {
if (Xrm.Page.ui.getFormType() !== 4 /* Disabled */ && Xrm.Page.ui.getFormType() !== 3 /* ReadOnly */) {
Xrm.Page.data.save().then(function (successResponse) {
_this.processOrderSuccessResponse();
}, ClientUtility.ActionFailedHandler.actionFailedCallback);
}
else {
_this.processOrderSuccessResponse();
}
};
this.processOrderSuccessResponse = function () {
var columns = new ODataContract.ColumnSet(false, ["invoiceid"]);
if (!_this.IsBackOfficeInstalled()) {
var convertSalesOrderToInvoiceRequest = new ODataContract.ConvertSalesOrderToInvoiceRequest();
convertSalesOrderToInvoiceRequest.SalesOrderId = { guid: Xrm.Page.data.entity.getId() };
convertSalesOrderToInvoiceRequest.ColumnSet = columns;
Xrm.WebApi.online.execute(convertSalesOrderToInvoiceRequest).then(function (response) {
response.json().then(function (jsonResponse) {
var invoiceId = jsonResponse.invoiceid;
Xrm.Utility.openEntityForm(Sales.EntityNames.Invoice, invoiceId, null);
});
}, ClientUtility.ActionFailedHandler.actionFailedCallback);
}
else {
var defaultStatusCode = -1;
XrmCore.Commands.Common.setState(Xrm.Page.data.entity.getId(), Xrm.Page.data.entity.getEntityName(), Sales.SalesOrderState.Submitted, defaultStatusCode);
}
};
this.IsBackOfficeInstalled = function () {
// var isBackOfficeInstalled: string = Xrm.Internal.getResourceString("IS_BACKOFFICE_INSTALLED");
// if (ClientUtility.DataUtil.isNullOrEmptyString(isBackOfficeInstalled)) {
// return false;
// }
// return isBackOfficeInstalled === "1";
//TODO: investigate backoffice.
return false;
};
this.GetProductsForOrder = function () {
_this.commandBarActions.getProducts();
};
this.LockSalesOrder = function () {
debugger;
_this.commandBarActions.lock();
};
this.UnlockSalesOrder = function () {
debugger;
_this.commandBarActions.unlock();
};
this.CloseOrder = function () {
_this.CloseOrFulfillOrder(Sales.SalesOrderState.Canceled);
};
this.FulfillOrder = function () {
_this.CloseOrFulfillOrder(Sales.SalesOrderState.Fulfilled);
};
this.IsSalesOrderActive = function () {
return _this.IsSalesOrderState(Sales.SalesOrderState.Active);
};
this.IsSalesOrderFulfilled = function () {
return _this.IsSalesOrderState(Sales.SalesOrderState.Fulfilled);
};
this.IsSalesOrderSubmitted = function () {
return _this.IsSalesOrderState(Sales.SalesOrderState.Submitted);
};
this.IsSalesOrderState = function (state) {
var stateCodeControl = Xrm.Page.data.entity.attributes.get("statecode");
var orderState = stateCodeControl ? stateCodeControl.getValue() : null;
var returnValue = false;
if (ClientUtility.DataUtil.isNullOrUndefined(orderState)) {
return returnValue;
}
switch (state) {
case 0:
if (orderState === 0) {
returnValue = true;
}
break;
case Sales.SalesOrderState.Submitted:
if (orderState === Sales.SalesOrderState.Submitted) {
returnValue = true;
}
break;
case Sales.SalesOrderState.Fulfilled:
if (orderState === Sales.SalesOrderState.Fulfilled) {
returnValue = true;
}
break;
case Sales.SalesOrderState.FulfilledOrActive:
if (orderState === Sales.SalesOrderState.Fulfilled || orderState === 0) {
returnValue = true;
}
break;
default:
returnValue = false;
break;
}
return returnValue;
};
}
Object.defineProperty(SalesOrderRibbonActionsLibrary.prototype, "commandBarActions", {
get: function () {
if (ClientUtility.DataUtil.isNullOrUndefined(this._commandBarActions)) {
this._commandBarActions = new Sales.SalesCommandBarActions();
}
return this._commandBarActions;
},
enumerable: true,
configurable: true
});
return SalesOrderRibbonActionsLibrary;
}());
Sales.SalesOrderRibbonActionsLibrary = SalesOrderRibbonActionsLibrary;
})(Sales || (Sales = {}));
/**
* #license Copyright (c) Microsoft Corporation. All rights reserved.
*/
/// <reference path="../../../../../TypeDefinitions/CRM/ClientUtility.d.ts" />
/// <reference path="UCI/SalesOrderRibbonActionsLibrary.ts" />
/// <reference path="../../../../../../references/internal/TypeDefinitions/XrmClientApi/XrmClassicWebClientApi.d.ts" />
var Sales;
(function (Sales) {
var SalesOrderRibbonActions = (function () {
function SalesOrderRibbonActions() {
}
return SalesOrderRibbonActions;
}());
SalesOrderRibbonActions.Instance = new Sales.SalesOrderRibbonActionsLibrary();
Sales.SalesOrderRibbonActions = SalesOrderRibbonActions;
})(Sales || (Sales = {}));
//# sourceMappingURL=SalesOrderRibbonActions.js.map
Previous version of this JS have function "fulfillOrder" and it was working properly. But in this version, they updated a lot. I don't know how to call it.
Please suggest.
Thank you.
If you are calling the methods outside then create an instance and call that FulfillOrder method,
var obj = new Sales.SalesOrderRibbonActionsLibrary();
obj.FulfillOrder(); // now call the methods
You need to call in the way mention below.
Sales.SalesOrderRibbonActionsLibrary.FulfillOrder();

How to access object properties from prototype in javascript? [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 6 years ago.
I have class below when I call printData I get this.collection is undefined.
How do I access this.collection from the prototype inside printData()? Or do i need to change the class structure. Actually the object returns function which intern returns object in hierarchy.
Thanks in advance!
Sample Class:
var DbProvider = (function () {
function DbProvider(db) {
var that = this; // create a reference to "this" object
that.collection = db;
}
DbProvider.prototype.create = function () {
return {
action: function () {
var y = {
printData: function () {
alert('Hello ' + this.collection.Name);
}
};
return y;
}
};
};
return DbProvider;
})();
Usage:
var a = new DbProvider({ "Name": "John" });
a.create().action().printData();
You could save the this reference and bind it to the printData function
var DbProvider = (function () {
function DbProvider(db) {
var that = this; // create a reference to "this" object
that.collection = db;
}
DbProvider.prototype.create = function () {
var self = this;
return {
action: function () {
var y = {
printData: function () {
alert('Hello ' + this.collection.Name);
}.bind(self)
};
return y;
}
};
};
return DbProvider;
})();
var a = new DbProvider({ "Name": "John" });
a.create().action().printData();
Or you could refactor a bit and move that to the outer scope of DbProvider and use that in printData
var DbProvider = (function () {
var that;
function DbProvider(db) {
that = this; // create a reference to "this" object
that.collection = db;
}
DbProvider.prototype.create = function () {
return {
action: function () {
var y = {
printData: function () {
alert('Hello ' + that.collection.Name);
}
};
return y;
}
};
};
return DbProvider;
})();
var a = new DbProvider({ "Name": "John" });
a.create().action().printData();
just need to keep track of the this pointer correctly, like this
var DbProvider = (function() {
function DbProvider(db) {
this.collection = db;
}
DbProvider.prototype.create = function() {
var self = this;
return {
action: function() {
var y = {
printData: function() {
alert('Hello ' + self.collection.Name);
}
};
return y;
}
};
};
return DbProvider;
})();
let dbProvider = new DbProvider({
Name: "test"
});
dbProvider.create().action().printData();
Keeping ES5 syntax and the call structure a solution would be:
var DbProvider = (function () {
function DbProvider(db) {
var that = this; // create a reference to "this" object
that.collection = db;
}
DbProvider.prototype.create = function () {
var that = this;
return {
action: function() {
var y = {
printData: function () {
console.log('Hello ' + that.collection.Name);
}
};
return y;
}
};
};
return DbProvider;
})();
Definitely not elegant but it works :)
If you do not want to change your structure, you can achieve this behavior if you change you functions to arrow functions.
var DbProvider = (function () {
function DbProvider(db) {
var that = this; // create a reference to "this" object
that.collection = db;
}
DbProvider.prototype.create = function() {
return {
action: () => {
var y = {
printData: () => {
alert('Hello ' + this.collection.Name);
}
};
return y;
}
};
};
return DbProvider;
})();
The way you are creating this "class" is definitely non standard. Let me know if you want an example of how to better structure it.

Creating a method similar to delay in my own class

I am trying to create a method similar to delay() from JQuery.
I am creating a method called $. Remember I am not using JQuery and don't want to for this problem.
function $(element) {
if(!(this instanceof $)) {
return new $(element);
}
this.element = document.querySelector(element);
}
$.prototype.color = function color(color) {
this.element.style.color = color;
}
I can use this method like so:
$('#foo').color('red);
It will change the color of #foo to red
What I am trying to do is set a delay before it changes the color. One way would be to do :
$.prototype.delay(time, fn) {
setTimeout(function() {
fn();
}, time);
}
and then call it like so:
$('#foo').delay(1000, function() {
$('#foo').color('red');
});
But that's not very useful, what I would like to do instead is use it like so:
$('#foo').delay(1000).color('red);
I found this but couldn't figure it out.
Thanks in advance,
I.L
One way of doing it (#georg)
// create a new instance if it doesn't already exists when $ is called
function $(element) {
if(!(this instanceof $)) {
return new $(element);
}
this.element = document.querySelector(element);
this.promise = Promise.resolve(this);
this.css = this.element.style;
}
// wrapper for the promise
$.prototype.method = function(name, fn) {
$.prototype[name] = function(...args) {
this.promise.then(self => fn.apply(self, args));
return this;
};
}
// delay method,
$.prototype.delay = function(time) {
this.promise = new Promise(
resolve => setTimeout(() => resolve(this), time));
return this;
}
// example of a method to change the color
$.prototype.method('color', function (color) {
this.css.color = color;
});
// used like so
$('#foo').delay(2000).color('green');
<div id="foo">Hi there!</div>
I have found another nice solution that allows to use delay multiple time see my answer for more details.
Here's an example with promises. Requires some more work to be practical, but should give you an idea. Basically, all methods like color should operate on "resolved this" instead of just "this":
function $(element) {
if(!(this instanceof $)) {
return new $(element);
}
this.element = document.querySelector(element);
this.promise = Promise.resolve(this)
}
$.prototype.color = function color(color) {
this.promise.then(function(self) {
self.element.style.color = color;
});
}
$.prototype.delay = function(n) {
this.promise = new Promise(
resolve => setTimeout(() => resolve(this), n));
return this;
}
$('#foo').color('red');
$('#foo').delay(1000).color('blue');
<div id="foo">foo</div>
For automated promisifying you can use a wrapper like this:
$.prototype.method = function(name, fn) {
$.prototype[name] = function(...args) {
this.promise.then(self => fn.apply(self, args));
return this;
};
}
and then, for example,
$.prototype.method('color', function (color) {
this.element.style.color = color;
});
Here is how jQuery implement it :
function (time, type) {
time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
type = type || "fx";
return this.queue(type, function () {
var elem = this;
setTimeout(function () {
jQuery.dequeue(elem, type);
},
time);
});
}
Using only* Queue :
function (type, data) {
if (typeof type !== "string") {
data = type;
type = "fx";
}
if (data === undefined) {
return jQuery.queue(this[0], type);
}
return this.each(function () {
var queue = jQuery.queue(this, type, data);
if (type === "fx" && queue[0] !== "inprogress") {
jQuery.dequeue(this, type);
}
});
}
And Dequeue :
function (type) {
return this.each(function () {
jQuery.dequeue(this, type);
});
}
The only external jQuery call in these functions is "jQuery.fx", with can be avoided.
From there, it will be easy to implement these 3 functions in your own model.
Using chainable methods and setting a delay method:
function $(element) {
if(!(this instanceof $)) {
return new $(element);
}
// select all elements with this identifier
this.elements = document.querySelectorAll(element);
// by default select the first element of querySelectorAll
this.element = this.elements[0];
this.css = this.element.style;
// first method applied will be exectuted directly
this.delayTime = 0;
}
$.prototype.$ = function position(pos) {
if(pos == 'first') {
pos = 0;
} else if(pos == 'last') {
pos = this.elements.length-1;
}
var that = this;
setTimeout(function() {
that.element = that.elements[pos] || that.elements[0];
that.css = that.element.style;
}, this.delayTime);
return this;
}
$.prototype.delay = function(delayTime) {
// set a delay for the following method applied
this.delayTime += delayTime;
return this;
}
// wraps the method into a setTimeout
$.prototype.method = function(name, fn) {
$.prototype[name] = function(...args) {
var that = this;
setTimeout(function() {
// method will only take one relevant parameter
fn(that, args[0]);
}, this.delayTime);
return this;
};
}
// CSS methods
$.prototype.method('backgroundColor', function(self, color) {
self.css.backgroundColor = color;
})
$('#foo').delay(1000).backgroundColor('blue').delay(1000).backgroundColor('white').delay(1000).backgroundColor('red');
#foo {
background-color: lightgrey;
}
<div id="foo">Hey there!</div>

Is it possible to unit-test this javascript structure?

Given the following JavaScript structure:
addClickEvent: function() {
element.addEventListener('click', function() {
self.a();
self.b();
});
},
Is it possible to assert that a() and b() have been called without refactoring out the anonymous function or editing it's contents?
Assuming the self in your code is the window.self property.
You could do something like this:
function element_onclick_callsAandB() {
// Arrange
var aCalled = false;
var bCalled = false;
var element = ...;
var origA = self.a;
var origB = self.b;
self.a = function() {
aCalled = true;
origA();
};
self.b = function() {
bCalled = true;
origB();
};
try {
// Act
element.click();
// Assert
assertTrue(aCalled);
assertTrue(bCalled);
}
finally {
self.a = origA;
self.b = origB;
}
}

… is not a function in javascript {custom code}

please, could somebody tell me, what he heck I am doing wrong in my syntax?
The problem starts in the statement this.form.onsubmit, where I get this.initData is not a function.
Thanks.
var Contact_Form = function(element){
this.form = element;
this.errors = new Array();
this.invalid = new Array();
this.inSent = false;
this.name = new String();
this.email = new String();
this.message = new String();
this.initData = function()
{
this.name = this.getElementValue('contact-name');
this.email = this.getElementValue('contact-email');
this.message = this.getElementValue('contact-message');
}
this.form.onsubmit = function(event)
{
event.preventDefault();
this.initData();
if(this.verifyData())
this.send();
}
this.verifyData = function()
{
if(!this.isNameLength())
this.setError('name', 'Zadejte, prosím, jméno dlouhé maximálně 30 znaků.');
if(this.isProperEmail())
{
if(!this.isEmailLength())
this.setError('email', 'Váš e-mail smí obsahovat maximálně 50 znaků.');
}
else
this.setError('email', 'Zadejte, prosím, email v korektním formátu.');
if(!this.isMessageLength())
this.setError('name', 'Zadejte, prosím, zprávu v rozsahu 1-999 znaků.');
this.doInvalidFields();
if(0 == this.errors.length)
return true;
return false;
}
this.doInvalidFields = function()
{
if(this.invalid.length > 0)
{
for(var invalid in this.invalid)
this.getElement(invalid).setAttribute('aria-invalid', true);
}
}
this.setError = function(field, message)
{
this.errors.push(message);
this.invalid.push(field);
}
this.getElementValue = function(element) {
return this.getElement(element).value;
}
this.getElement = function(element) {
return document.getElementById(element);
}
this.getElementName = function() {
return this.getElement('contact-name');
}
this.getElementEmail = function() {
return this.getElement('contact-email');
}
this.getElementMessage = function() {
return this.getElement('contact-message');
}
this.isNameLength = function(){
return this.isLength(this.name, 1, 30);
}
this.isEmailLength = function(){
return this.isLength(this.email, 1, 50);
}
this.isMessageLength = function(){
return this.isLength(this.email, 1, 999);
}
this.isProperEmail = function() {
return this.email.match(/^(?:\w){1,100}#{1}(?:\w){1,100}(?:.){1}(?:\w){1,10}$/ig);
}
this.isLength = function isLength(string, _min, _max) {
if(string.length >= _min && string.length <= _max)
return true;
return false;
}
}
window.onload = function()
{
new Contact_Form(document.forms[0]);
}
The problem is that this is not inherited, and has a different value inside each function.
Then, use
var Contact_Form = function(element){
/* ... */
var that = this;
/* Here this===that */
this.form.onsubmit = function(event)
{
/* Here this===that.form */
event.preventDefault();
that.initData();
if(that.verifyData())
this.send();
}
/* ... */
}
this is referring to the form in the onsubmit handler. You could assign this to a local variable, or bind the handler to the correct this with Function.prototype.bind, ie:
this.form.onsubmit = function(event) {
event.preventDefault();
this.initData();
if(this.verifyData())
this.send();
}.bind(this)
or with jQuery.proxy
this.form.onsubmit = $.proxy(function(event) {
event.preventDefault();
this.initData();
if(this.verifyData())
this.send();
}, this);
Both examples are forcing the this context of the function to be the instance of a Contact_Form whenever the handler is called

Categories

Resources