I am building a simple validation library and I need to use Proxy because I want to accept custom validation rules as chain object. I build something and its works properly on modern browsers but not works on IE11, I tried with proxy-polyfill but its also not work properly. My proxy code is below.
function contextProxy(context) {
return new Proxy(context, {
get(obj, prop) {
if (prop in obj) {
return obj[prop];
}
const newContext = contextProxy(context._clone());
if (definedRules.hasOwnProperty(prop)) {
return newContext._takeRule(definedRules[prop]);
}
if (customRules.hasOwnProperty(prop)) {
return newContext._takeRule(customRules[prop]);
}
},
});
}
And I use that proxy;
function validationL() {
return contextProxy(new ValidationLContext());
}
And I have definedRules object;
const definedRules = {
numeric: function () {
return function (text) {
return /^\d+$/.test(text);
};
},
lowercase: function () {
return function (text) {
return /^([a-z]+\s*)+$/.test(text);
};
},
uppercase: function () {
return function (text) {
return /^([A-Z]+\s*)+$/.test(text);
};
},
minLength: function (min) {
return function (text) {
return text.length >= min;
};
},
maxLength: function (max) {
return function (text) {
return text.length <= max;
};
},
alphaNumeric: function () {
return function (text) {
return /^([a-zA-Z0-9 _-]+)$/i.test(text);
};
},
specialChars: function () {
return function (text) {
return !/^([a-zA-Z0-9 _-]+)$/i.test(text);
};
},
email: function () {
return function (text) {
return /^([a-zA-Z0-9_.+-])+\#(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/.test(
text
);
};
}
};
ValidationLContext.js
function ValidationLContext(isNot = false, chain = []) {
this.chain = chain;
this.isNot = isNot;
}
ValidationLContext.prototype.not = function () {
this.isNot = true;
return this;
};
ValidationLContext.prototype._takeRule = function (ruleFn) {
return (...args) => {
this.chain.push({ fn: ruleFn.apply(this, args), isNot: this.isNot });
if (this.isNot) {
this.isNot = false;
}
return this;
};
};
ValidationLContext.prototype.validate = function (text) {
return this.chain.every((c) =>
c.isNot ? !c.fn.call(this, text) : c.fn.call(this, text)
);
};
ValidationLContext.prototype._clone = function () {
return new ValidationLContext(this.isNot, this.chain);
};
export default ValidationLContext;
So library usage like this;
validationL().numeric().minLength(3).validate("123");
validationL().not().numeric().minLength(3).validate("123");
I can use like above on modern browsers like Chrome but when I try on IE11 only not() function works so only objects functions can work.
Can anyone help me with this.
Related
I have LIVR in a project i'm working now and is quite unclear to me how this work. I can't understand how to create new rules for custom validation.
Here's the code:
LIVR.Validator.defaultAutoTrim(true);
let validator = new LIVR.Validator({});
LIVR.Validator.registerDefaultRules({
nested_object_value() {
return function (value) {
if (!value || (value && !value.value || value === [])) {
return 'REQUIRED';
}
return '';
};
},
max_number_advancement() {
return function (value) {
if (value > 100) {
return 'MAX_NUMBER';
}
return '';
};
},
required_if_activity_present() {
return function (value, allValue) {
if (allValue.activitycycletype && !value || allValue.requestpeople === []) {
console.log(first)
return 'REQUIRED_IF_CYCLETYPE';
}
return '';
};
},
});
And this is how its used:
validationForm = () => {
const { formValue, updateErrors } = this.props;
const validData = validator.validate(formValue);
console.log(formValue)
if (!validData) {
const errorsValidator = validator.getErrors();
if (errorsValidator && Object.keys(errorsValidator).length > 0) {
const newErrors = {};
Object.keys(errorsValidator).forEach((error) => {
newErrors[error] = errorsValidator[error];
});
updateErrors(newErrors);
}
blame(t('validation-error'));
return false;
}
updateErrors({});
return true;
}
Opening the form with this validation in the app, seems to call only the last method required_if_activity_present().
What i expect here is that i can create a new method inside registerDefaultRules(), that is a LIVR method, like this:
LIVR.Validator.registerDefaultRules({
re quired_not_empty() {
return function (value) {
if (!value) {
return 'REQUIRED';
}
return '';
};
},
... //other methods
}
but seems not working, the newer method is not being called at all by validator.validate()
Anyone know how to create a new rules where i can check if an element inside the object that has to be validate is an empty array?
Because seems that LIVR doesn't return a validation error in this case, but only on empty string and null values.
Thanks in advance
I use Angular 1.5 and I made a factory function which is return a literal object like this:
return {
item: null,
get: function() {
return item;
},
create: function() {
if (this.get()){
this.remove();
}
this.item = {};
},
remove: function() {
var item = this.get();
if (item) {
this.item = null;
}
},
add: function() {
if (!this.get()) {
this.create();
}
this.item.newprop = 'value';
}
}
please do not ask me to change to function declaration. I want a object with his own actions(functions) and properties that is working on.
This pattern (like get inside create so on..) I didn't copied from anywhere. so I'm wonder if has a name? It is best way to deal with function-black boxes?
What is the best way to put Promise inside? so every function should return a promise
every then function I need to use bind???
todo like this:
create: function () {
this.get()
.then(remove)
.then(function () {
this.item = {}; // BUT this === undefined!!
});
}
You have to use bind in every then callback function:
var myModule = {
item: null,
get: function() {
return Promise.resolve(this.item);
},
create: function() {
return this.remove().then(function() {
this.item = {};
}.bind(this));
},
remove: function() {
return this.get().then(function(item) {
if (item) {
this.item = null;
}
}.bind(this));
},
add: function() {
return this.get().then(function(item) {
return item || this.create();
}.bind(this)).then(function() {
this.item.newprop = 'value';
}.bind(this));
}
}
// Let see it working:
myModule.create().then(function() {
return myModule.get();
}).then(function(item) {
console.log("After create: ", item);
return myModule.remove();
}).then(function() {
return myModule.get();
}).then(function(item) {
console.log("After remove: ", item);
return myModule.add();
}).then(function() {
return myModule.get();
}).then(function(item) {
console.log("After add: ", item);
});
I wrote the following code (page object pattern). Works correctly.
However, I don't like this, because I can't remove "then" from "pressHelpLink". Instead add the code in getElementByLink.
I would like to see ElementFinder Promise (instead of ManagedPromise) as result of getElementByLink("Help")
How nicely solve selenium promise?
var self = Page.create({
url: {value: ''},
// function:
getElementByLink: {
value: function (link) {
return element.all(by.repeater('items')).then(function (el) {
var my_array = el.map(function (el) {
return el.element(self.by.xpath('a'));
});
var element_array_finder = protractor.ElementArrayFinder.fromArray(my_array);
var element = element_array_finder.filter(function (el) {
return el.getText().then(function (text) {
return text === link;
})
});
return element;
}).then(function (element) {
world.expect(element.length).equal(1);
return element[0];
});
}
},
// elements:
HelpLink: {
get: function () {
return self.getElementByLink('Help');
}
},
// method:
pressHelpLink: {
value: function () {
return self.HelpLink.then(function (el) {
return el.click()
});
}
},
});
Why not use cssContainingText? Maybe something like...
// elements:
HelpLink: {
get: function () {
return element(by.cssContainingText('a', 'Help');
}
},
// method:
pressHelpLink: {
value: function () {
return self.HelpLink.click()
}
},
I want the use set method of factory but both of return default how can I fix that problem?
app.factory("DualListShareFactory", function(){
var selectedArray=[];
return{
getSelectedArray: function () {
return selectedArray;
},
setSelectedArray: function (array){
selectedArray=array;
}
}
});
Using ng-dual List from https://github.com/tushariscoolster/ng-duallist
I'm tkining it not working: DualListShareFactory.setSelectedArray(vm.rightValue);
I use other method for and push but I am received same error .
app.controller("duallist2", function($scope,DualListShareFactory){
var vm=this;
vm.property='duallist2';
activate();
function activate() {
vm.leftValue = [];
vm.rightValue = [];
vm.addValue = [];
vm.removeValue = [];
function loadMoreLeft() {
for (var i = 0; i < $scope.incomingItem.length; i++) {
vm.leftValue.push({
'name': $scope.incomingItem[i]
});
}
};
function loadMoreRight() {
}
vm.options = {
leftContainerScrollEnd: function () {
},
rightContainerScrollEnd: function () {
},
leftContainerSearch: function (text) {
console.log(text)
vm.leftValue = $filter('filter')(leftValue, {
'name': text
})
},
rightContainerSearch: function (text) {
vm.rightValue = $filter('filter')(rightValue, {
'name': text
})
},
leftContainerLabel: 'Gelen Parçalar',
rightContainerLabel: 'Seçilen Parçalar',
onMoveRight: function () {
console.log('right');
console.log(vm.addValue);
},
onMoveLeft: function () {
console.log('left');
console.log(vm.removeValue);
}
};
loadMoreLeft();
var leftValue = angular.copy(vm.leftValue);
var rightValue = angular.copy(vm.rightValue);
} console.log(vm.rightValue);
DualListShareFactory.setSelectedArray(vm.rightValue);
});
I am not this will work but try "this",
app.factory("DualListShareFactory", function(){
this.selectedArray=[];
return{
getSelectedArray: function () {
return this.selectedArray;
},
setSelectedArray: function (array){
this.selectedArray = array;
}
}
});
var app = angular.module("testapp", ["ng-duallist"]);
app.factory("DualListShareFactory", function(){
var selectedArray = [];
return{
getSelectedArray: function () {
return selectedArray
},
setSelectedArray: function (array){
angular.copy(array, selectedArray);
}
}
});
using for this add the other code block before ending function.
onMoveRight: function () {
DualListShareFactory.setSelectedArray(vm.rightValue);
},
onMoveLeft: function () {
DualListShareFactory.setSelectedArray(vm.rightValue);
}
};
loadMoreLeft();
var leftValue = angular.copy(vm.leftValue);
var rightValue = angular.copy(vm.rightValue);
I have this code (also shown below) that is giving me an error in IE8 but is fine in Chrome and PhantomJS.
The error is "Object doesn't support this property or method knockout-2.2.1.debug.js, line 2319 character 35", which is called from currentPage(pages[pages.indexOf(current) + steps]);
I have no clue why it's not working, so any help would be greatly appreciated!
var Page = (function () {
function Page(index, name, canNavigateToPage, navigatedToThisPage) {
this.index = index;
this.name = name;
this.canNavigateToPage = canNavigateToPage;
this.navigatedToThisPage = navigatedToThisPage;
}
Page.prototype.navigateToPage = function () {
if (this.canNavigateToPage()) {
this.navigatedToThisPage(this);
}
};
return Page;
})();
var AccountSearchParameters = (function () {
function AccountSearchParameters() {
this.reference = ko.observable();
this.scheme = ko.observable();
this.lastName = ko.observable();
this.sufficientInputToSearchForAccount = ko.computed(function () {
return this.reference() && this.scheme() && this.lastName();
}, this);
}
return AccountSearchParameters;
})();
function viewModel() {
var self = this,
currentPage = ko.observable(),
accountSearchParameters = new AccountSearchParameters(),
forwardPageProgressionGuards = {
'1': function canMoveToPage2() {
return accountSearchParameters.sufficientInputToSearchForAccount();
},
'2': function canMoveToPage3() {
return true;
},
'3': function canMoveToPage4() {
return true;
}
},
canMoveToNextPage = function (currentlyOnPage) {
function disallowPageMovementNotExplicitlyDefined() {
return false;
}
return (forwardPageProgressionGuards[currentlyOnPage] || disallowPageMovementNotExplicitlyDefined)();
},
canMoveToPreviousPage = function (currentlyOnPage) {
return currentlyOnPage > 1;
},
pages = [
new Page(1, 'Customer details', function () {
return true;
}, function (page) {
currentPage(page);
}),
new Page(2, 'Bank details', forwardPageProgressionGuards['1'], currentPage),
new Page(3, 'Payment details', forwardPageProgressionGuards['2'], currentPage),
new Page(4, 'Confirmation', function () {
return true;
}, currentPage)],
pageNavigator = function (canNavigate, steps) {
current = currentPage();
console.log(canNavigate(current.index));
if (canNavigate(current.index)) {
currentPage(pages[pages.indexOf(current) + steps]);
}
};
currentPage(pages[0]);
self.page = ko.computed(function () {
return currentPage();
});
self.accountSearchParameters = accountSearchParameters;
self.nextPage = function () {
pageNavigator(canMoveToNextPage, 1);
};
self.previousPage = function () {
pageNavigator(canMoveToPreviousPage, -1);
};
self.canMoveToNext = ko.computed(function () {
return canMoveToNextPage(currentPage().index);
});
return self;
}
$(function () {
ko.applyBindings(viewModel());
});
indexOf in IE8 does not supported, use $.inArray