FluentValidation: Only do .Must when field is not empty - fluentvalidation

I would like to only check for a .Must condition when a field is not empty/null.
The following code is not evaluation .Must properly (.CheckUrl not being called) when bad urls are passed.
RuleFor(c => c.Website)
.Must((item, list, context) => ValidationHelper.CheckUrl(item.Website, context))
.When(x => !string.IsNullOrEmpty(x.Website));
I want to fail the validation only if something is passed for url, empty should not fail it.
I could change the .CheckUrl method to return true if url empty and remove the .When but i prefer not to do that if there is a way around the validation rules itself

Related

Cypress Get Attribute value and store in Variable

I want to get the Attribute value and store in a variable how we can achieve this in cypress
In my case I want to get the complete class value and store it in variable.
This code just give me the attribute class value but how I can store the fetch value in variable
cy.get('div[class*="ui-growl-item-container ui-state-highlight ui-corner-all ui-shadow ui-growl-message"]').invoke('attr', 'class')
I was trying to compare the style of one element with another to make sure they were equal. Here's the code that seems to work for me.
cy.get('.searchable-group-selector-card-image')
.eq(4)
.invoke('attr', 'style')
.then(($style1) => {
const style1 = $style1
})
A good way to solve this kind of scenario is to use the alias mechanism. One could leverage this functionality to enqueue multiple elements and then check all of them together by chaining the results. I've recently come to a case in an SPA where the assertion had to happen between elements that were spread across different angular routes (call them different pages).
In your use case, this would like:
cy.get('.searchable-group-selector-card-image')
.eq(4)
.invoke('attr', 'style')
.as('style_1')
cy.get('.another-element')
.invoke('attr', 'style')
.as('style_2')
// later on for example you could do
cy.get('#style_1').then(style_1 => {
cy.get('#style_2').then(style_2 => {
// Both values are available and any kind of assertion can be performed
expect(style_1).to.include(style_2)
});
});
This is described in Variables and Aliases section of the Cypress Documentation.
Here is how I got the value of for attribute in a label tag which had text "Eat" inside.
cy.contains('Eat').then(($label) => {
const id = $label.attr('for');
}
Most important thing is to get the selector right, so it exactly finds the value you are looking for. In this case you already found it. By using then() gives you the ability to store it in a variable.
cy.get('div[class*="ui-growl-item-container ui-state-highlight ui-corner-all ui-shadow ui-growl-message"]').invoke('attr', 'class')
.then($growl-message => {
const message = $growl-message.text()
//do the checks with the variable message. For example:
cy.contains(message)
})
Note that the scope of the variable is within the curly brackets. Thus using the variable has to be within those curly brackets.

Aurelia - Custom validation to check if a form has changes

I see THIS question regarding whether the form I am validating has changed.
However it has nothing to do with Aurelia validation and I would like to validate whether the form has any changes upon clicking the save button. I dont want to do it on the server.
What I have done is to save the values I fetched initially so I can do a comparison.
fetch("/api/Client/editClient/" + parms.id, {
method: "GET",
headers
})
.then(response => response.json())
.then(data => {
this.client.deserialize(data);
this.originalClient === this.client;
})
original client is the unmodified object.
I have created a custom validation function however its not working as intended.
I thought I could use the current value and then compare it to the original value.
ValidationRules.customRule(
'changesExist',
(value, obj, fetchedEntity) =>
fetchedEntity != value,
'No changes detected'
);
When I try and use it I find it erroring:
// Validation Rules.
ValidationRules
.ensure(a: ClientDetails) => a).satisfiesRule('changesExist', this.originalClient);
I am unsure how to make this work. What I want is a validation that compares the orginalClient object with the the one that is to be sent back to the server. This way I can check if there is reason for sending it back can saving it to the database...
It's rather brute force, but this will likely do what you want:
JSON.stringify(fetchedEntity) !== JSON.stringify(value)
The app-contacts sample app does it using an areEqual function. Have a look at the repo and you can see how it's used and how you could adapt it for your purposes.
function areEqual(obj1, obj2) {
return Object.keys(obj1).every((key) => obj2.hasOwnProperty(key) && (obj1[key] === obj2[key]));
};

Yii 1 Pagination takes every params user inserted

I have my pagination url set to
www...com/category/detail.html?page=2
For which my code is,
$dataProvider = new CActiveDataProvider('Page', array('criteria' => array('condition' => 'status=1', 'condition' => 'category_id=' . $categoryObject -> id, 'order' => 'postDate DESC'), 'pagination' => array('pageSize' => 4,'pageVar'=>'page'), ));
$dataProvider->getData();
var_dump $dataProvider->totalItemCount;
I am getting the exact data counts and my pagination url seems working. I have my URL rule configured as
'index'=>'site/index',
'contact'=>'site/contact',
'privacy'=>'site/privacy',
'sitemap.xml'=>'site/sitemap',
'<category:\w+>' => 'category/detail',
'<category>/page/<page:\d+>' => 'category/detail',
'<category>'=>'category/detail',
'<category:\w+>/<postTitle:.+>' => 'category/post',
'<category:\w.+>/<postTitle:.+>'=>'category/post',
my auto generated pagination URl are working fine but,
If I manually insert url something like
www......com/category/detail.html?Page_page&page=2
www......com/category/detail.html?Page_pizza&page=2
or any stupid things I can put they navigates to the page.
Now, here I want to remove these extra parameters or I want my pagination url to be strict to
www...com/category/detail.html?page=2
and if I put any additional params I want an error page.
I have been working in this for 2 weeks and tried every possible ways I could.
You should set the "params" property of the pagination to an empty array:
'pagination' => array('pageSize' => 4,'pageVar'=>'page', 'params' => array()),
This will avoid exclude any GET parameters from pagination links(if you need any included, add their name there).
To throw an error, you need to check for the parameters in your action.
// remove valid prameters from get array.
$arr = array_diff_key($_GET, array_flip(array('page', 'postTitle', 'category')));
// if still there are parameters left, throw an error.
if(count($arr) > 0) {
throw new CHttpException('invalid parameter');
}

Conditional Validation doesn't update when property changes

How do I use conditional validation based on a property that can change?
The following validation rules will only validate if the toValidate flag is set to true.
ValidationRules.ensure('Email').required().when(v => v.toValidate);
get toValidate() {
if (this.checkBox.Checked)
return true;
}
else {
return false;
}
}
So when toValidate is set to true the required() rule will be ran.
If the value of toValidate changes due to the user making a change to say a checkbox on the page the validation rule is not affected and will stay either on or off depending on what it was on first loaded.
Is there a way to allow the conditional rule to be applied on the fly?
A validation rule will only be re-run when the property in the ensure() function changes. If you want to re-run a validation rule (or rules) on some other change, then you can do so manually.
Run all rules:
this.controller.validate();
Run one rule:
this.controller.validate({ object: this.yourObject, propertyName: "Email" });
You can setup observers in various different ways to initiate this - that's another topic!

Aurelia validation: applying some rule on change and some on blur on same property

I have an input field for a value that should have exactly 5 digits. I would like to show errors when typing characters other than digits immediatly (onChange) but showing the error for unsufficient string length only on blur.
My rule looks like so at the moment:
ValidationRules
.ensure("myInput")
.matches(new RegExp(/[0-9]/))
.minLength(5)
.on(this);
MaxLength is restricted by setting maxlength in html.
If I set the validation trigger to "onChange" to get an immediate response to wrong characters I also get an error shown for not satisfying the minLength rule while typing correct digits until having typed 5 of them.
The behavior I would like to have is to apply the matches-rule onChange and the minLength-rule onBlur.
Is there any possibility to apply two rules on the same property on different events? I know how to validate manually but I don't know how to differenciate between rules.
You can use the when fluent API to satisfy your needs. Something like this -
ValidationRules
.ensure('email')
.email()
.required()
.when((order) => {
if (order.length > 4) {
order._ruleHasBeenMet = true;
}
return order.length > 4 && order._ruleHasBeenMet;
}
.withMessage('Email is required when shipment notifications have been requested.');
Encouraged by #PWKad's answer I played a little with .when() and came up with this:
I changed the validate trigger to "validateOnChangeAndBlur" and added a reference to my field:
<input type="text" value.bind="myInput & validateOnChangeAndBlur" maxlength="5" ref="myInputRef">
I extended the validation rule with a conditional validation checking if my input has focus as I only want to validate length when the input loses focus:
ValidationRules
.ensure("myInput")
.matches(new RegExp(/[0-9]/))
.minLength(5)
.when(() => this.dwKapitel !== document.activeElement)
.on(this);
This works like I expect it to work.