AngularJS concatenate two functions - angularjs

I have two factories (because it is more readable) and one controller.
I do not know if it is possible, but I want to sent the result of the two factories in one variable.
code
vm.result = [];
vm.validate = validate;
function validate(password1, password2) {
vm.result = comparePasswordFactory.compare(password1, password2) + validNumberFactory.valid(password1);
return vm.result;
}
compare returns:
return {
color: 'green',
text: 'Passwords match',
validate1: 'true'
};
valid returns:
return {
text: 'Number should be between 12 and 45',
validate2: 'false'
};
I do not think what I wrote is correct.
But, is this possible and/or is it a good option ?

in order to validate using both functions you have to read and compare its validate1 / validate2 properties
var passwordOK = comparePasswordFactory.compare(password1, password2).validate1 === 'true';
var numberOK = validNumberFactory.valid(password1).validate2 === 'true';
vm.result = passwordOK && numberOK;
tip: better way would be to use boolean values instead of string, eg.
return {
validate: false
}
pro way: consider using consistent api in your factories, then you could do something like:
var validators = [comparePasswordFactory, validNumberFactory];
var isValid = true;
for(var i=0;i<validators.length;i++){
if(!validators[i].validate.call(this, password1, password2)){
isValid = false;
break;
}
}
vm.result = isValid;
then you could easily add another validator (notice that all factories must implement validate method)

Related

single requirement in parsley error message %s1

Hi I have a custom validator with 2 requirements(arguments/paramaters) in parsley.js
For the error message I only want to display one of the requirements but I cannot work out how
messages: {en: 'You must choose at least one language with %s'},
I thought %s1 or %s0 might work but they don't
%s results in this message:
You must choose at least one language as [native,enrolment_form_new_instruction_languages_proficiency]
but I just want
You must choose at least one language as native
here is my full validator in case that helps you answer:
Parsley.addValidator('oneChildEquals', {
requirementType: ['string', 'string'],
validateString: function(_value, requirement, requirement2, instance) {
var $inputs = $(instance.element).find("select.language-proficiency");
var valid = false;
$inputs.each(function(i){
if($(this).val() == requirement){
valid = true; // one input has the target value (requirement2)
return false; //break out of the loop
}
});
// no input has the target value (requirement2)
return valid;
},
messages: {en: 'You must choose at least one language with %s'},
});
I have written a solution, probably could be improved, but I don't even know if I need this now. Anyway in case anyone else does, you can just add this code:
if(typeof(string) === 'string' && typeof(parameters) === 'string' && parameters.match(/^\[.*\]$/) && string.match(/\%s\d/)){
//parameters are an array of values and string is trying to access them individually with %s1 to get first etc
var paramsArray = parameters.slice(1, parameters.length-1).split(',');
var interpolations = string.match(/\%s\d/g);
for(var j = 0; j < interpolations.length ; j++){
var interpolation = interpolations[j];
var number = parseInt(interpolation.replace("%s", ''));
if(isNaN(number)){
string = string.split(interpolation).join(interpolation + '[not a valid interpolation]');
}else {
var val = paramsArray[number-1];
if(typeof(val) === 'undefined'){
val = interpolation + '[not a valid interpolation]';
}
string = string.split(interpolation).join(val);
}
}
return string
}
after this code in the source
formatMessage: function formatMessage(string, parameters) {
if ('object' === _typeof(parameters)) {
for (var i in parameters) {
string = this.formatMessage(string, parameters[i]);
}
return string;
}
and before
return 'string' === typeof string ? string.replace(/%s/i, parameters) : '';
Then it supports things like
Parsley.addValidator('testParsley', {
requirementType: ['string','string'],
validateString: function(_value, requirement, requirement2) {
return (_value === requirement || _value === requirement2);
},
messages: {en: 'test parsley this field must equal %s1 or %s2'}
});

How to filter the objects with multiple values?

I have the array of objects. when I require to filter the object by single vaue i am doing like this:
$scope.filteredByPhase = $filter('filter')($scope.allApps, {Phase:"All"});
$scope.allAppsBatch = $scope.filteredByPhase;
But as a option, I would like to filter the objects by 2 'Phase` values by "All" or "Home" in this case how to filter?
I tried like this:
$scope.filteredByPhase = $filter('filter')($scope.allApps, {Phase:("All" || "Home")});
$scope.allAppsBatch = $scope.filteredByPhase;
But not works.. any one guide me please?
In AngularJS, you can use a function as an expression in the filter. In the function you can validate the condition and return Boolean value. All the falsy items are filtered out of the result. So you can do
$scope.filteredByPhase = $filter('filter')($scope.allApps, function (app) {
if (app.Phase == "All" || app.Phase == "Home") {
return true;
}
return false;
});
Read More : AngularJS Filter Documentation
Use $filter passing an anonymous comparison function.
$scope.filteredItems = $filter('filter')($scope.items, function (item) {
return (item.Phase == "all") ? true : false;
});
Keep in mind that you may use Array.filter as well:
$scope.items = [{
Phase: "home"
}, {
Phase: "all"
}, {
Phase: "all"
}, {
Phase: "home"
}];
console.log($scope.items);
$scope.filteredItems = $scope.items.filter(function (item) {
return (item.Phase == "all") ? true : false;
})
console.log($scope.filteredItems)
You may also trigger multiple filtering actions using chaining:
$scope.fi = $scope.i.filter(func1).filter(func2);

Prevent multiple submits in angularjs

I'm looking for a AngularJS-based way to prevent multiple submits per task.
I don't need buttons to be disabled after submission or close the form and wait for the task to be completed. Instead, I need requests to be unique.
To be more detailed, I need $http.get and $http.post stop sending multiple same requests.
Any Ideas?
According to this article, you can use provider decorator.
NOTE: this approach is based on angular-api
https://gist.github.com/adambuczynski/354364e2a58786e2be71
UPDATE
I've changed a little part in your suggested solution, because returned promises have lost .success and .error and .then.
Just use this edited code to have all of those functions working:
.config(["$provide", function ($provide) {
$provide.decorator('$http', function ($delegate, $q) {
var pendingRequests = {};
var $http = $delegate;
function hash(str) {
var h = 0;
var strlen = str.length;
if (strlen === 0) {
return h;
}
for (var i = 0, n; i < strlen; ++i) {
n = str.charCodeAt(i);
h = ((h << 5) - h) + n;
h = h & h;
}
return h >>> 0;
}
function getRequestIdentifier(config) {
var str = config.method + config.url;
if (config.data && typeof config.data === 'object') {
str += angular.toJson(config.data);
}
return hash(str);
}
var $duplicateRequestsFilter = function (config) {
if (config.ignoreDuplicateRequest) {
return $http(config);
}
var identifier = getRequestIdentifier(config);
if (pendingRequests[identifier]) {
if (config.rejectDuplicateRequest) {
return $q.reject({
data: '',
headers: {},
status: config.rejectDuplicateStatusCode || 400,
config: config
});
}
return pendingRequests[identifier];
}
pendingRequests[identifier] = $http(config);
$http(config).finally(function () {
delete pendingRequests[identifier];
});
return pendingRequests[identifier];
};
Object.keys($http).filter(function (key) {
return (typeof $http[key] === 'function');
}).forEach(function (key) {
$duplicateRequestsFilter[key] = $http[key];
});
return $duplicateRequestsFilter;
})
}])
It could be a performance issue but following idea could solve your problem.
Store the each request URL and DATA as key value pair on a variable. URL should be KEY. For Same URL multiple submission can be stored in a Array.
Then for any new call check the URL if it present in your stored object, then compare the data with each object thorughly (deep check, it is costly though).
If any exact match found then stop the processing. As same request came.
Other wise proceed and don't forget to store this data also.
But it is costly since need to check the data which could be havy.
Note: At the time of storing the data you could convert it to JSON String so it will be easier to compare between String.
here is the Code Algo
YourService.call(url, params) {
var Str1 = JSON.stringify(params);
if(StoredObj[url]) {
for each (StoredObj[url] as Str){
if(Str === Str1) {
return;
}
}
}
else {
StoredObj[url] = []; //new Array
}
StoredObj[url].push(Str1);
Call $http then;
}

How do I filter by 'keywords' with angular.js?

I'm trying to create a robust filtering system with basic HTML & angular.js, so far with the help of a few kind people on here, I've ended up with this:
http://codepen.io/liamtarpey/pen/jfvDK
It works fine, the only issue is if you type something backwards, for example if the user searches for: 'taco mexican' or even 'mexican taco', you'd get no results at all.
Is there a way to use the filter as more of a keyword filter rather than a string filter?
You will have to iterate through every property for every word in the search term. This works:
$scope.search = function(user) {
var match = true;
$scope.query.split(" ").forEach(function(word) {
if (match === true) {
var wordMatch = false;
for (var prop in user) {
if (user.hasOwnProperty(prop)) {
if(user[prop].toLowerCase().indexOf(word.toLowerCase()) > -1) wordMatch = true;
}
}
}
match = wordMatch;
});
return match
}

Clearing fields with angular?

When the user clicks on a radio button I run:
$scope.clientClick = function() {
//do stuff
}
I have a form, and I would like half of the fields on the form to be cleared in the above method.
I have done:
$scope.clientClick = function() {
$scope.entry.first_name = '';
$scope.entry.last_name = '';
$scope.entry.email = '';
$scope.entry.tel = '';
$scope.entry.gender = '';
$scope.entry.job = '';
$scope.entry.age = '';
}
But is there an easier way rather than listing each field again?
Short answer
['first_name', 'last_name', ...].forEach(function (f) {
$scope.entry[f] = '';
});
Long answer
In JavaScript, properties can be accessed in two ways:
obj.prop
obj['prop']
You can keep a list of strings with the properties that you want to clear, and then just iterate over it clearing each in turn.
I'd suggest that if you have a dependency to the radio button then the view model should reflect that it could be cleared:
$scope.entry.dependant = { first_name: '' ... }
$scope.clientClick = function() {
$scope.entry.dependant = {};
}
function initObject(obj) {
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
switch(typeof obj[i]){
case 'string':
obj[i] = '';
break;
case 'number':
obj[i] = 0;
break;
}
}
}
}
Use this function. NEVER do this $scope.entry = {} or $scope.entry.name = null, it's safer and you won't get unnecessary errors when you have some parts of your code that expect a type. It's a lot easier just to set a string to "".
I would use $scope.entry = null or $scope.entry = {}.
Make code simple and readable.
I would have done some thing like Reset a model with angular.js:
$scope.initial = [
{
first_name : '',
last_name : '',
email : '',
tel : '',
gender : '',
job : '',
age : ''
}
];
Demo
$scope.clientClick = function() {
angular.copy($scope.initial, $scope.entry);
});

Resources