Vee-Validate validateAll() with scope - javascript

I have a scenario where I have sectioned out (scoped) a form so that I can validate small chunks at a time using the following function.
validateScope (scope) {
return this.$validator.validateAll(scope);
}
I want to do one final validation of the entire form before I submit it to the server; however, validateAll() doesn't seem to pick up inputs that have been added to a scope. I've also tried just validating each scope and then submit the form if they are ALL valid, but I am not sure how to do that since everything is asynchronous.
validateAll () {
let valid = true;
// Not sure how to build this function since validateScope is asynchronous
_.each(this.names, (name, index) => {
if (this.validateScope(`name-${index}`)) {
valid = false;
}
});
return valid; // Always returns true even though the _.each should set it to false
}

As mentioned in my comment, your code will end up looking something like this:
validateAll () {
let valid = true;
let validations = []
_.each(this.names, (name, index) => {
validations.push(this.validateScope('name-' + index))
});
return Promise.all(validations)
// consolidate the results into one Boolean
.then(results => results.every(r => r))
}
Then, of course, you'll have to use validateAll as a promise:
this.validateAll().then(isValid => {
if (!isValid) {
//do whatever you need to do when something failed validation
} else {
// do whatever you need to do when everything is valid here
}
})

Related

Javascript childArray.filter() nested within parentArray.map() isn't filtering

I would like to return an updated array to state, so I am using map with filter as follows:
state.assignmentClusters.map(cluster => {
cluster.files.forEach(file => {
file.motifList.filter(motif =>{
return motif.motif_id !== state.motifIdToDelete;
});
});
});
Since I need to return an array, I am using map() on first array, the 2nd one (file) i'm just going over it without expecting to mutate anything, so I used forEach() and in the last depth, I am using filter() to return all motifs except for those that their id is equal to state.motifIdToDelete (just fyi, both IDs are strings).
PS, this piece of code is within a Vue mutation function that allows me to mutate state (like reducer in react).
What am I doing wrong here?
Thanks,
bud.
I have solved this differently yet I would like to grant the answer to the person who can show me how to preform this correctly with filter()
this currently works:
state.assignmentClusters.forEach(cluster => {
cluster.files.forEach(file => {
file.motifList.forEach((motif, index) =>{
if (motif.motif_id == state.motifIdToDelete) {
file.motifList.splice(index, 1)
}
});
});
});
Your call to state.assignmentClusters.map returns nothing. You should return cluster in the arrow function.
Also, your call to file.motifList.filter doesn't mutate anything. You must use the value returned by the filter function somewhere.
state.assignmentClusters.map(cluster => {
cluster.files = cluster.files.map(file => {
file.motifList = file.motifList.filter(motif => {
return motif.motif_id !== state.motifIdToDelete;
});
return file;
});
return cluster;
});
Another option if mutation doesn't matter:
state.assignmentClusters.forEach(cluster => {
cluster.files.forEach(file => {
file.motifList = file.motifList.filter(motif => {
return motif.motif_id !== state.motifIdToDelete;
});
});
});

make variable available in other function

I have a function
function formSubmitListener() {
$(".js-form").submit(event => {
event.preventDefault();
let input = fetchInput();
validateInput(input);
if (isValid) {
serverCall()
}
});
}
validateInput returns a isValid boolean of true (if all fields on a form have been filled out) that I need to make available for the if statement. If at all possible I want to prevent the use of a global variable.
How do I make the boolean available ?
function formSubmitListener() {
$(".js-form").submit(event => {
event.preventDefault();
let input = fetchInput();
let isValid = validateInput(input);
if (isValid == true) {
serverCall()
}
});
}
this might be what you want. set the validateInput(input) function call to a variable and use that variable since it will store the true/false.
or another way by putting the direct function in the if where it checks whats returned
function formSubmitListener() {
$(".js-form").submit(event => {
event.preventDefault();
let input = fetchInput();
if (validateInput(input)) {
serverCall()
}
});
}

How to do non short circuit condition in Typescript?

How to evaluate condition in non short circuit way in typescript?
Typescript does not allow & or | for boolean type.
The reason why I need a non short circuit checking is I call showErrors in function isValueValid.
Given this function
function isValue1Valid(){
if(value1 === 0) return true;
showErrors1();
return false;
}
function isValue2Valid(){
if(value2 === 0) return true;
showErrors2();
return false;
}
Then in my condition
if(isValue2Valid() & isValue2Valid()){
//Submit data
}
Although I can do it like this one
if(isValue2Valid() & isValue2Valid()){
//Submit data
return;
}
showErrors1()
showErrors2()
But I feel to call it inside isValueValid function. In reality I always think to call show errors by default whenever there's an error.
To answer your question, you could do
if ([isValue2Valid(), isValue2Valid()].every(Boolean)) {
//Submit data
}
to evaluate all function calls and then combine their values. But you really shouldn't have isValueValid call showError in the first place. Instead, make your test functions return the error messages, and then if there are any, show them:
function getValue1Error() {
if (value1 === 0) return null;
else return "error1";
}
function getValue2Error() {
if (value2 === 0) return null;
else return "error2";
}
// then:
const errors = [getValue1Error(), getValue2Error()] // or even better, just a loop over your fields
if (errors.some(Boolean)) {
for (let error of errors)
showError(error);
} else {
// Submit data
}
If you want to use functions with side-effects (which is not a good idea in general), it might help to be very explicit about what is called and when:
var value1Valid = isValue1Valid(); // might show some messages
var value2Valid = isValue2Valid(); // might show some more messages
if (value1Valid && value2Valid) {
// submit data
}

Knockout custom computed looses validation rules

I've created a custom function as seen below. It works perfekt while storing data and updating the observable MetaData values etc, but it breaks when it comes to validation.
I am using Knockout validation and have been debugging for a few hours and what I THINK i found out is the fact that the validation is run twice and the second time, all the rules of my observable has dropped, so every time the observable is valid, since there are no rules. The later code is copied from the source code here: https://github.com/Knockout-Contrib/Knockout-Validation/blob/master/Dist/knockout.validation.js
Why are my custom function making the observable dropping the validation rules?
My custom function
ko.observable.fn.valueByKey = function (key) {
return ko.computed({
read: function () {
var md = ko.utils.arrayFirst(ko.unwrap(this), function (item) {
return item.Key() == key;
});
if (md === null) {
md = new MetaData({ Key: key });
this.push(md);
}
return md.Value();
},
write: function (value) {
var md = ko.utils.arrayFirst(ko.unwrap(this), function (item) {
return item.Key() == key;
});
md.Value(value);
}
}, this);
};
Code that runs twice
var h_obsValidationTrigger = ko.computed(function () {
var obs = observable(),
ruleContexts = observable.rules();
console.log(ruleContexts);
exports.validateObservable(observable);
return true;
});
Another important part of knockout validation js
addRule: function (observable, rule) {
observable.extend({ validatable: true });
//push a Rule Context to the observables local array of Rule Contexts
observable.rules.push(rule);
return observable;
},
UPDATE 1:
I've come up with a simple solution that almost seems to work.
ko.observable.fn.valueByKey = function (key) {
var md = ko.utils.arrayFirst(ko.unwrap(this), function (item) {
return item.Key() == key;
});
if (md === null) {
md = new MetaData({ Key: key });
this.push(md);
}
return md.Value;
}
When using this, I get validation message on the element, but error-count does not rise on my view model, so the viewmodel it self is still valid, even though i get validation error.

Breeze - Lazy Load Navigational Property

New to breeze - I have a breeze entity, that has an array navigational property in a one to many relationship. I'd like to check if the parent entity has any related child entities existing in the navigational property. This child array has not been expanded, and I'd like to lazy load for the check.
With the load happening asynchronously, it seems it may not be loaded by the check
(if entity.children()...).
It would seem I'd have the same issue if I put the check in the "then" callback. Is there a way to synchronously load the child array so that I can do the check and return whether populated or not? Or is there a better way to do this?
function doChildrenExist (entity) {
var childrenExist = false;
entity.entityAspect.loadNavigationProperty("children")
.then(function () {})
.fail(function () {});
if(entity.children() !== null || entity.children().length > 0) {
childrenExist = true;
}
return childrenExist;
}
There is no way to synchronously load a navigation property, ( this is the nature of ajax), but you are on the right track with the loadNavigationProperty. You could do something like the following where you pass in a callback function that will be called with either "true" or "false" depending on whether children exist.
function doChildrenExist(entity, callback) {
entity.entityAspect.loadNavigationProperty("children").then(function () {
// this syntax assumes knockout model library.
var childrenExist = entity.children().length > 0;
callback(childrenExist);
}).fail(function () {
...
});
}
The reason this is not returning what you would like right now is because you are returning the childrenExist before the async query has completed. Putting the function inside your .then() will catch the call back, and only return IT'S callback once the data has been retrieved, unless it fails, in which case we can return an error or simply 'false'.
function doChildrenExist (entity) {
var childrenExist = false;
entity.entityAspect.loadNavigationProperty("children")
.then(function () {
if(entity.children().length > 0) {
childrenExist = true;
}
return childrenExist; })
.fail(catchError);
function catchError(e) {
alert(e.message);
return false;
}
}
to save a few bytes of code you should be able to do this as well -
function doChildrenExist (entity) {
// No need to define a variable since we are either returning true or false
entity.entityAspect.loadNavigationProperty("children")
.then(function () {
if(entity.children().length > 0) {
return true;
}
return false; })
.fail(catchError);
function catchError(e) {
alert(e.message);
return false;
}
}
and in your function that is calling doChildrenExist -
var showChildren = ko.observable(false); // Do something like hide children until they exist
function refresh(entity) {
doChildrenExist(entity)
.then(checkResult)
}
function checkResult(result) {
showChildren(result);
}

Categories

Resources