I have this post method
$.post("/abc/export.action",
{
sessiontoken: sessiontoken,
exportType: "xls",
param1:compareData,
param2:comparePatchData},
function(resdata)
{
alert(resdata);
}
);
I wanted some best practice so that I can have enumeration or array which stores all my post parameters in it and use it while post, A way in which I can avoid hardcoding of sessiontoken, param1 etc.. what could be the solution?
EDIT
Sometimes it might happen that I need to change the names of params so i have to edit everywhere I have post method, instead of that if all the params where there in some enum or array it would be much easier to just change at one place.
If you want the labels in a object to be based on some other variable you can do it with
var paramLabels = {"session": "sessionToken", "type": "exportType", ...}
var paramValues = {};
paramValues[paramLabels.session] = sessionToken;
paramValues[paramLabels.type] = "xls"
...
$.post(/"abc/export.action", paramValues, function(resdata) { alert(resdata);});
I can't really see the benefit of this approach expect when the developers of the backend like to change the names of the parameters every five minutes.
Another way of handling this would be to create a factory method or a builder
function createParams(session, type, ...) {
return { "sessionToken": session, "exportType": type, ...) }
}
var params = createParams(sessionToken, "xls", ...);
or
var Parameters = function() {
this.session = function(session) { this.session = session; return this;}
this.type = function(type) { this.type = type; return this;}
...
this.build = function() {
var params = {}
!this.session || params.sessionToken = this.session;
!this.type || params.exportType = this.type;
...
return params;
}
}
var params = new Parameters().session(sessionToken).type("xls")...build();
Both of these approaches let you define the concreate name of the parameters only once. The latter may be easier to reuse when different set of parameters are needed.
Instead of passing an object literal to $.post() you can pass an object that was defined elsewhere in your code, and thus re-use that same object for multiple posts. Or put in a function call that returns an object with the appropriate parameters set up.
var postParams = {
sessiontoken: sessiontoken,
exportType: "xls",
param1:compareData,
param2:comparePatchData
};
$.post("/abc/export.action",
postParams,
function(resdata) { alert(resdata); });
$.post("/abc/import.action",
postParams,
function(resdata) { alert(resdata); });
// or use a function that can return a different object
// depending on some conditions (or parameters passed to
// the function though I haven't shown that)
function getPostParams() {
if (someCondition)
return postParams;
else
return {
sessionToken : something,
// etc.
};
}
$.post("/abc/someother.action",
getPostParams(),
function(resdata) { alert(resdata); });
Related
I have created a JS class. Here is following code:
export default class Service {
constructor(
serviceId,
serviceName,
serviceDescription,
serviceImageName,
categoryId,
servicePrice,
currencyCode,
acceptPayment,
serviceDuration,
multipleBookingPerSlot,
mode,
tzSupport,
minOptionCount
) {
try{
this.id = serviceId;
this.title = serviceName;
this.subTitle = serviceDescription;
this.imageUrl = serviceImageName;
this.categoryId = categoryId;
this.price = servicePrice;
this.currencyCode = currencyCode;
this.acceptPayment = acceptPayment;
this.meetingDuration = serviceDuration;
this.multipleBookingPerSlot = multipleBookingPerSlot;
this.serviceName = serviceName;
this.mode = mode;
this.tzSupport = tzSupport;
this.session = minOptionCount
} catch(e){
if(e instanceof ReferenceError){
console.error("Service data missing.")
}
}
}
}
My goal is whenever new object of Service creates like new Service('1') if any of key is missing code should throw error and stop execution. How can i achieve this?
You won't get a ReferenceError if the caller doesn't supply enough arguments, you'll just see undefined in the parameters.
You have 13 parameters (which is far, far too many). You could do the brute-force thing:
if (arguments.length < 13) {
throw new Error("Missing arguments");
}
Instead, though, I suggest using the builder pattern or an options object instead of 13 discrete parameters. More than three parameters is fairly hard to manage.
For instance, with an options object:
export default class Service {
constructor(
options
) {
["id", "title", "subTitle", "imageUrl", "categoryId", "price", "currencyCode",
"acceptPayment", "meetingDuration", "multipleBookingPerSlot", "serviceName",
"mode", "tzSupport", "session"].forEach(name => {
if (!options.hasOwnProperty(name)) {
throw new Error(name + " is a required option");
}
});
Object.assign(this, options);
}
}
Usage:
let s = new Service({id: 1, title: "foo", /*...etc...*/});
That way, the caller isn't lost in a sea of parameters.
However, if it's important to validate the parameter values are present, isn't it important to validate their values, too? Nothing's to stop me from calling new Service with 13 completely-invalid arguments (undefined repeated 13 times, for instance).
So I would probably use an options object (because it's much easier for the caller) combined with parameter destructuring, and then individual validation, e.g.:
export default class Service {
constructor({ // <== Notice the {
id,
name,
decription,
imageUrl,
categoryId,
price,
currencyCode,
acceptPayment,
meetingDuration,
multipleBookingPerSlot,
mode,
tzSupport,
minOptionCount
}) { // <== And the }
this.id = validate.positiveNumber(id);
this.title = validate.nonBlank(name);
this.subTitle = validate.nonBlank(description);
this.imageUrl = validate.URL(imageUrl);
this.categoryId = validate.positiveNumber(categoryId);
this.price = validate.price(price);
this.currencyCode = validate.currencyCode(currencyCode);
this.acceptPayment = validate.boolean(acceptPayment);
this.meetingDuration = validate.duration(meetingDuration);
this.multipleBookingPerSlot = validate.boolean(multipleBookingPerSlot);
this.serviceName = this.title; // Already validated
this.mode = validate.mode(mode);
this.tzSupport = validate.tzSupport(tzSupport);
this.session = validate.whateverThisIs(minOptionCount);
}
}
...where validate is a set of reusable validations. Usage is the same as above:
let s = new Service({id: 1, title: "foo", /*...etc...*/});
As i already commented assigning undefined to an objects property is completely valid. The solution might be to check for the values of the arguments Arraylike against undefined:
constructor(a,b,c){
if(arguments.length!=3){//check length
return;
}
for(var a=0;a<arguments.length;a++){
if(arguments[a]===undefined){//check against undefined
return;
}
}
//your code
}
http://jsbin.com/vugepakama/edit?console
When you want to validate breeze-entity you write:
this.entityAspect.validateEntity()
But what about if I want to fire validations only for complex-type, without fire the entire-entity validations?
complexType.complexAspect not have method validateEntity.
So, what should I do?
Edit after I saw Jay answer:
I tried to use method validateProperty.
But the result was that it always returns true, becouse it not check each one of the properties.
So, I tried to call method validateProperty several-times, each time for other field of the complexType. It give me boolian-result of valid/not valid, but not update the validation-errors.
Here is the code that I tried after I saw Jay answer, but it is not help:
validateSingleField(myComplexProertyName);
first version of validateSingleField function: (the result was that it always returns true, becouse it not check each one of the properties)
function validateSingleField(object, fieldName) {
var entityAspect = object.entityAspect;
var objectType = object.entityType;
var prop = objectType.getProperty(fieldName);
var value = object.getProperty(fieldName);
if (prop.validators.length > 0) {
var context = { entity: entityAspect.entity, property: prop, propertyName: fieldName };
if (entityAspect._validateProperty(value, context)) {
return true;
}
return false;
}
}
second version:(It give me boolian-result of valid/not valid, but not update the validation-errors.)
function validateSingleField(object, fieldName) {
var aspect = object.entityAspect || object.complexAspect;
var entityAspect = object.entityAspect || object.complexAspect.getEntityAspect();
var objectType = object.entityType || object.complexType;
var prop = objectType.getProperty(fieldName);
if (prop.isComplexProperty) {
var isOk;
objectType.getProperties().forEach(function (p) {
isOk = isOk && validateSingleField(object[fieldName](), p.name)//writing 'object[fieldName]()' - is for send the entire complexType of the entity
});
return isOk;
}
else {
{
var value = object.getProperty(fieldName);
if (prop.validators.length > 0) {
var context = { entity: entityAspect.entity, property: prop, propertyName: fieldName };
if (entityAspect._validateProperty(value, context)) {
return true;
}
return false;
}
}
}
}
There is no separate method to validate a complex type because the validation results are all part of the 'parent' entity. Complex type properties are considered part of the entity, not independent entities.
What you can do is call validateProperty on the 'complex' property of the parent entity.
Given that I have a class defined such as
(function () {
function Dummy(){
var toReturn ={
myProp : "asdf",
myFunc : myFunc
}
return toReturn;
function myFunc(){};
}
})();
how does one get an instance of the same type after
var dummy = new Dummy();
JSON.stringify(dummy);
so that I have myFunc still available on the type.
JSON.parse(JSON.stringify(dummy)) returns same shape of the object by not the same type.
NOTE: I am not asking about capability of JSON, but how do people deal with this in general. Do you hand roll your mapping mechanism so that after parsing from JSON you map it onto instance of the type, or if there is such functionality in some library, such as underscore.
I created a helper function that helps me do this, but would like to hear from others how do you deal with situation like this. As I put in comments, JSON comes over the wire, for which we have a type defined. To get the values from JSON in our type, we parse json, create instance of type and then apply map function below.
function map(fromObj, toObj) {
Object.keys(fromObj)
.forEach(function (key) {
if (typeof fromObj[key] != 'function') {
if (toObj.hasOwnProperty(key)) {
if (typeof fromObj[key] !== 'object') {
toObj[key] = fromObj[key];
} else {
map(fromObj[key], toObj[key]);
}
}
}
}
});
}
Note, Not certain about requirement , if this similar to what posed at Question. If off-topic , please post comment , will withdraw.
Piece was originally composed for this Question Organizing large javascript files [on hold] . With a json response , having "x" type of contents , could map returned object to new object , copying properties utilizing $.extend() .
Result would be new object having both properties and functions of returned data. At piece below, at completion of process , $.Pages begins as function , then type gets converted to object - though it could retain both function and object properties by including || {} at definition stage.
Functions within returned json objects could be called within .then() callback ; see console at jsfiddle , object init functions.
At conclusion , $.Pages object has properties of returned json , including access to functions . Based on a jsonp - type processing flow.
Piece is "frame" of a processing approach ; could extend to include other functionality
$(function() {
var dfd = new $.Deferred();
dfd.progress(function(msg) {
console.log(msg);
});
ProductPage = {
name : "ProductPage",
addToCartBtn: "#add-to-cart",
initName : function() {return dfd.notify(this.name)},
init: function() {
this.initName();
// ProductPage.initAddToCartPopup();
// ProductPage.initSidebar();
}
};
ContactPage = {
name : "ContactPage",
validateEmail : function (e) {return dfd.notify(e)},
initName : function() {return dfd.notify(this.name)},
init: function() {
this.initName();
// ProductPage.initAddToCartPopup();
// ProductPage.initSidebar();
}
};
var mods = function() {
return {"ContactPage" : ContactPage
, "ProductPage" : ProductPage };
};
$.Pages = function() {
$.when(mods())
.done(function(pages) {
$.Pages = pages;
});
return $.Pages
};
$.when($.Pages())
.then(function() {
$.each($.Pages, function(k, v) {
v.init();
})
});
console.log($.Pages)
});
jsfiddle http://jsfiddle.net/guest271314/60kv2439/1/ (see console)
basic approach
$p = {};
var queue = [];
var mods = ["dep1.json", "service1.json"];
var mod = function(m) {
queue.push(m);
if (queue.length === mods.length) {
$.each(queue, function(k, v) {
$p = $.extend(v, $p)
})
}
};
$.each(mods, function(k, v) {
$.getScript(v, function(script, status, jqxhr) {
console.log($p)
})
})
I have got a little dilema what to do (What should I do). I've got in my app several places where I am using AJAX to transfer a JSON data. So for example receiving a data from the registration form:
try {
var data = JSON.parse(json);
}
catch(e) {
// ...
}
var fields = {
firstName: data.firstName || "",
lastName: data.lastName || "",
...
};
Then I need to do something with these fields. Let's say:
if (fields.firstName) {
// OK save it to the DB
}
if(fields.lastName.xxx()) { // xxx() is a method that belongs to JS String Object
// Do something...
}
The problem is what if fields.firstName or fields.lastName is {} / []? That may happen if somebody sent a modified JSON with a wrong data types, the whole app will then crash since the method xxx is missing.
Do I have to check the type of every field whether it is really a string, a number, an array... or is there some another maybe nicer way how to do this?
Unfortunately that's a problem you'll have to face anytime using a dynamic language like JavaScript.
One possible solution is not using String methods, but creating a function that will check it's arguments first:
// original, with string methods
if (text instanceof String && text.trim().length === 0) { ... }
// alternative, define function first
var isEmptyString = function(text) {
if (!(text instanceof String)) throw new Error("Argument must be a String");
return text.trim().length === 0;
}
// use it in your code
if (isEmptyString(text)) { ... }
That can lead to cleaner code.
Just be sure not to define those functions in a global scope, when you have to use them in a Browser. Within the node.js modules that should not be a problem.
You'll have to make a little validator. Like that:
var format = {
foo: "string",
bar: "string"
};
var data = {
foo: "bar",
bar: []
}
var validate = function (data, format) {
for(var d in data) {
if(typeof data[d] !== format[d])
return false;
}
return true;
}
console.log(validate(data, format));
You can also remove invalid data like this:
var format = {
foo: "string",
bar: "string"
};
var data = {
foo: "bar",
bar: []
}
var validate = function (data, format) {
for(var d in data) {
if(typeof data[d] !== format[d])
delete data[d];
}
return data;
}
console.log(validate(data, format));
In addition to what Tharabas suggests, you could take advantage of the 2nd argument of JSON.parse for doing your sanity check:
JSON.parse(data, function(key, value) {
return key === 'firstName' ? cleanup(value) : '';
});
See this page for further information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse
always in the process of learning Javascript and modifying a cool autocomplete library, i am now in front of this :
i need to check if something passed in an object literal is a variable/field (that is to be considered as a simple value) or is something that can be called.
(as MY autocomplete depend on many input fields, i need to "value" the right things, just before the Ajax.Request) so that this declaration (see the 'extra' parts...)
myAutoComplete = new Autocomplete('query', {
serviceUrl:'autoComplete.rails',
minChars:3,
maxHeight:400,
width:300,
deferRequestBy:100,
// callback function:
onSelect: function(value, data){
alert('You selected: ' + value + ', ' + data);
}
// the lines below are the extra part that i add to the library
// an optional parameter, that will handle others arguments to pass
// if needed, these must be value-ed just before the Ajax Request...
, extraParametersForAjaxRequest : {
myExtraID : function() { return document.getElementById('myExtraID').value; }
}
see the "1 // here i'm lost..." below, and instead of 1 => i would like to check, if extraParametersForAjaxRequest[x] is callable or not, and call it if so, keeping only its value if not. So that, i get the right value of my other inputs... while keeping a really generic approach and clean modification of this library...
{
var ajaxOptions = {
parameters: { query: this.currentValue , },
onComplete: this.processResponse.bind(this),
method: 'get'
};
if (this.options.hasOwnProperty('extraParametersForAjaxRequest'))
{
for (var x in this.options.extraParametersForAjaxRequest)
{
ajaxOptions.parameters[x] = 1 // here i'm lost...
}
}
new Ajax.Request(this.serviceUrl, ajaxOptions );
You can do a typeof to see if the parameter is a function, and call it if it is.
var value;
for (var x in this.options.extraParametersForAjaxRequest)
{
value = this.options.extraParametersForAjaxRequest[x];
if (typeof(value) == 'function') {
ajaxOptions.parameters[x] = value();
}
else {
ajaxOptions.parameters[x] = value;
}
}
if (typeof this.options.extraParametersForAjaxRequest[x]==='function') {
}
You should also do this:
if (this.options.extraParametersForAjaxRequest.hasOwnProperty(x) {
if (typeof this.options.extraParametersForAjaxRequest[x]==='function') {
}
}
when iterating through properties of objects, otherwise you can end up looking at prototype members too.
Another suggestion is to make this more readable with an alias for the thing you're working with. So the ultimate would be:
var opts = this.options.extraParametersForAjaxRequest;
// don't need to check for existence of property explicitly with hasOwnProperty
// just try to access it, and check to see if the result is
// truthy. if extraParametersForAjaxRequest isn't there, no error will
// result and "opts" will just be undefined
if (opts)
{
for (var x in opts) {
if (opts.hasOwnProperty(x) && typeof opts[x]==='function') {
}
}
}