window.Parsley.addValidator('passwordValidChars', {
requirementType: ['integer', 'integer'],
validateString: function(value, min, max) {
var invalidChars = [];
for (var i = 0; i < value.length; i++) {
if(value.charCodeAt(i) < min || value.charCodeAt(i) > max) {
invalidChars.push(value.charAt(i));
}
}
return (invalidChars.length === 0)
},
messages: {
en: 'These characters are not allowed %s'
}
});
I have this custom validator which validates the password entered between specific char codes e.g [33, 126].
If the user entered any invalid characters I collect them to an array invalidChars and then I want to pass the invalidChars array to the error message but how can I do that? The only values I can pass to the message are the min and max.
There's no super easy way, but you can return a dynamic error message. It's not well documented, but instead of returning false return $.Deferred().reject('your dynamic error message').
Related
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'}
});
This might be less difficult than I'm making it out to be, but I'm trying to make a Discord.JS bot command, that will take however many arguments I have. For example: !randomize 1,2,3,4,5,6,7,8,9,10
And the bot would respond with something like: "I have chosen: 4,2,7,3,9!" Any help?
Current attempt: Not exactly sure what I'm doing.
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}`
`bot.on('message', async msg => {
if(msg.content === "!add") {
//message.member.user.tag
var msgArray = msg.content.split(" ");
var args = msgArray.slice(1);
var user = args[1];
//if(!args[1]) return msg.channel.send("Please specify an argument!");
if(nameList.includes(user)) {
msg.reply("You're already on the list.")
} else {
nameList.push(args[1]);
msg.channel.send(`${args[1]} has been added to the list!\n Current List:` + nameList);
}
}
if(msg.content === "!bonus") {
if(nameList.length === 0) {
msg.reply("Either the list is empty, or I'm not in the mood!");
} else {
shuffleArray(nameList);
var chosenOne = nameList.pop();
nameList = [];
msg.reply(chosenOne + ' has been chosen! Good luck!');
}
}
if(msg.content === "!list") {
if(nameList.length === 0) {
msg.channel.send("Either the list is empty, or I'm not in the mood!");
} else {
msg.channel.send('The current list:' + nameList);
}
});```
Here's some simple steps to select 5 random elements from an array...
Construct an array of possible selections. In this example I've used names for the first 10 letters of the alphabet. In your code, it'll be the command arguments or predefined nameList.
Make a new array to hold the elements picked.
At some point before #3, you should check to make sure the pool the user has provided is large enough to make 5 selections (Array.length).
Use a for loop to execute the next code multiple times.
Generate a random number representing the index of a selected element (Math.random(), Math.floor()/double NOT bitwise operator).
Push the selection into the array.
Remove the chosen element from the original pool (Array.splice()).
Return the results.
const pool = ['Albert', 'Bob', 'Charlie', 'David', 'Edward', 'Francis', 'George', 'Horacio', 'Ivan', 'Jim'];
const selected = [];
for (let i = 0; i < 5; i++) {
const num = ~~(Math.random() * pool.length);
selected.push(pool[num]);
pool.splice(num, 1);
}
console.log(`I have chosen: ${selected.join(', ')}`);
Take this example and manipulate it within your code to suit your purpose.
I have a deeply nested object. I have some records which contain 2 fields that show keys of object properties. I also have select needed to search records by property of object and input to search by key of object. So if I choose option1 and type in input some text, it will be shown the matches in the first field (not second!). And it's similar for second field.
How I try to realize:
I wrote a filter http://plnkr.co/edit/z9DEmfYz2grW9UonLcFK?p=preview
.filter('appFilter', function() {
return function(value, select, input) {
var result = [];
input = input.toLowerCase();
var reg = new RegExp(input,'g');
if (angular.isArray(value)) {
if (input === '' || $scope.isFiltering) {
return value;
} else if (select.value === 'Sequence') {
for (let i = 0; i < value.length; i++) {
if (value[i].Sequence.toLowerCase().match(reg)) {
result.push(value[i]);
}
}
return result;
} else if (select.value === 'ID') {
for (let i = 0; i < value.length; i++) {
if (angular.isArray(value[i].Document)) {
for (let j = 0; j < value[i].Document.length; j++) {
if (value[i].Document[j].ID.toLowerCase().match(reg)) {
result.push(value[i]);
}
}
}
}
return result;
} else {
console.log('error');
}
}
}
})
In controller I set to select's ng-model first option: $scope.selectParameter = $scope.parameter[0];
In debug I set to input parameter some value (123 for example).
So I searching record by first field that contains 123 value. And result finds and pushes the object. But in browser shows anything.
What's the problem? And I can't avoid the empty option with '?' value in my select :(
UPDATED
Nearly solve my problem: http://plnkr.co/edit/z9DEmfYz2grW9UonLcFK?p=preview
It filters by appropriate field and input value. But I faced with another troubles.
When input is empty it doesn't show any record. And second is when I choose second option (ID) filter duplicates some records.
Also I try to switch off filter without clearing the input text by clicking on checkbox.
It's what I want to do but it doesn't work:
else if (input === '' || $scope.isFiltering) {
return value;
}
$scope.isFiltering is ng-model for checkbox input
I tried using angulars default filter. I'm not sure if this is exactly what you want, but maybe it helps a little.
.filter('appFilter', function($filter) {
return function(value, select, input) {
if( !angular.isDefined(input) || input.length < 1) {
return value;
}
// Angulars "filter" lets you pass in a object-structure to search for nested fields.
var query =
(select.value === 'Sequence') ?
{Sequence:input} : {Document:{ID:input}};
return $filter('filter')(value, query);
}
})
http://plnkr.co/edit/Egkw9bUvTPgooc0u2w7C?p=preview
I have an array like this in angular
app.myStringArray=
[ 'abcdefg',
'123456',
'qwerty'
];
Currently I have a common method that checks for value being in array like this
app.factory('commons', function () {
var commons= {};
//Checks if the current url is
commons.checkString= function (str) {
if (app.myStringArray.indexOf(str) > -1) {
return true; //current string is in list
} else {
return false;
}
}
return commons;
}
);
This works if I send in the full string 'abcdefg' or '123456' or 'qwerty'.
How can I make it work even if I get part of the string like for eg: 'bcd' ?
To check if a string contains another one you can use String.indexOf() or as of ES6 String.includes().
To check if at least one item in an array matches a predicate you can use Array.some() or simply iterate over the array yourself.
ES6 solution:
function checkString(str) {
return myStringArray.some(s => s.includes(str));
}
ES5 solution:
function checkString2(str) {
return myStringArray.some(function(s) {
return s.indexOf(str) > -1;
});
}
Iterate through the array and check indexOf(str) for each string in the array. No need for Angular.
var array = ['abcdefg', '123456', 'qwerty'];
function checkString(str) {
for (var i = 0; i < array.length; i++) {
if (array[i].indexOf(str) > -1) {
return true;
}
}
return false;
}
alert(checkString("bcd"));
I'm trying to achieve a kind of generic remaining function. I have a bunch of fields in my form, for example: name and address. These fields have a limit of characters size, my goal is to make a generic function to limit it's size when reached. So I made a sample function that works:
First on the page:
label(for='name') Name {{remaining()}} of {{totalChars}}
Second, the code to handle it:
$scope.totalChars = 10;
$scope.remaining = function() {
var count = 0;
if ($scope.mName) {
count = $scope.mName.length;
if (count > $scope.totalChars) {
$scope.mName = $scope.mName.trim().substr(0, $scope.mName.length - 1);
count = $scope.mName.length;
}
}
return count;
//return calculateChars($scope.mName, $scope.totalChars);
};
When I type some input value into name field, angular stops typing when 10 chars are reached as well. But I've remade the function to turn it in a generic way and try to use it for any field I want to, but doesn't work as expected:
$scope.totalChars = 10;
$scope.remaining = function() {
return calculateChars($scope.mName, $scope.totalChars);
};
...
function calculateChars(obj, size) {
var count = 0;
if (obj && obj !== 'undefined') {
count = obj.length;
if (count > size) {
$scope.obj = obj.trim().substr(0, obj.length - 1);
console.log('Result: ' + $scope.obj);
count = obj.length;
}
}
return count;
}
The calculateChars works partiality fine, the problem is $scope.obj = obj.trim().substr(0, obj.length - 1); because angularjs doesn't know what "obj" is and doesn't stop typing when 10 chars are reached, even counting the amount correctly.
I don't know how to make the first approach works for any case without duplicate any code for any text field I want to.
Thanks in advance!
It sounds like you're looking for a directive. Here's an example of a directive named remaining that, given a model and a "max length" attribute, displays how many characters are remaining. It also prevents the user from typing more than the max number of characters; this can be removed by getting rid of the first branch of the if (remaining < 0) check in the link function.
app.directive('remaining', function() {
return {
template: "{{remaining}} of {{maxLen}}",
scope: {
maxLen: '#max',
model: '=ngModel'
},
link: function(scope, elem, attrs) {
scope.$watch('model', function(val) {
if (val == null || val == undefined) return;
var maxLen = parseInt(scope.maxLen, 10);
var remaining = maxLen - val.length;
if (remaining < 0)
scope.model = val.substr(0, maxLen);
else
scope.remaining = remaining;
});
}
};
});
Here's a jsFiddle to demonstrate: http://jsfiddle.net/BinaryMuse/JanZm/. Note I'm using version 1.1.x of AngularJS to get access to the ngTrim directive, which tells Angular not to strip off whitespace in text fields.