I've got a custom list that contains multi collumns. The validation is made by a custom contenttype. Now I want a combination of two columns to be unique. Until know I did not found a way to solve this problem with on-board functions, so my idea was to use the eventreceiver or a customcontenttype.
What I tried:
ListEventReceiver
public override void ItemAdding(SPItemEventProperties properties)
{
if (properties.AfterProperties["a1"].ToString() == properties.AfterProperties["a2"].ToString())
{
properties.Status = SPEventReceiverStatus.CancelWithError;
properties.Cancel = true;
properties.ErrorMessage = "Failure";
}
base.ItemAdding(properties);
}
It works fine, but the error message is not show as a validation error. It is a new errorpage.
CustomContenttype
If I try to validate in a custom contenttype I can not access the value of an other field from the contenttype. So I can not compare two fields or check they are unique.
if you want to validation using ItemEventReceiver than you should use Sharepoint Error message page.
its will so you better of your Errormessage.I have used it.
Like :
if (properties.AfterProperties["a1"].ToString() == properties.AfterProperties["a2"].ToString())
{
properties.Status = SPEventReceiverStatus.CancelWithRedirectUrl;
properties.RedirectUrl = properties.WebUrl + "/_layouts/error.aspx?ErrorText=Entry is Failure";
}
or another way is Use PreSaveAction with javascript able to do valiation on list's forms.
Related
I need to get some data from service and display it in HTML. I have put API call in service, and I got that data in ts file(checked in console), But When I am trying to get the same data into html, its showing null reference exception. Couldnt figure out what I missed.
export class SsoComponent implements OnInit {
public samlResponseData: SamlResponse;
constructor(
private ssoService: SsoService,
private store: Store<AppState>) { }
ngOnInit() {
this.verifySessionExpiration();
}
public verifySessionExpiration() {
this.store.pipe(select(getAuthData))
.subscribe(authData => {
if (authData) {
this.ssoService.fetchSamlResponse()
.subscribe(samlResponse => {
console.log(samlResponse);
this.samlResponseData = samlResponse;
});
} else {
this.ssoService.goLogin();
}
});
}
I am seeing the correct response in console. This is my code in HTML.
{{samlResponseData.ResponseData}}
I am getting a console error saying, "Unable to set property 'ResponseData' of undefined or null reference"
I have a model SamlResponse with a string property that I want to show it in HTML.
Please help.
The logic you have in verifySessionExpiration() asynchronous. You are getting that error because your template is trying to access samlResponseData before it has a value.
One way to fix it would be to only render the data when you know the value isn't null or undefined.
<ng-container *ngIf="samlResponseData">
{{samlResponseData.ResponseData}}
</ng-container>
Another option would be to initialize samlResponseData to some empty object:
samlResponseData = {};
Basis of my questions is a simple form. Let's say we have 4 fields
Surname
Name
Question: Do you have a cat?
What's your cat's name
a submit button
Surname and question and cat's name are required fields. If Yes is the answer, the field cat's name is becoming visible.
So far so good. I am using FluentValidation to validate these fields. In my validator, I create the rule for these 3 properties of my viewmodel.
Now I'd only like to validate cat's name, if it's visible. There is no way to remove rules. I also tried with behaviors, but at the time I click submit (which executes the save method in my viewmodel), I don't have access to my behaviors..
What's the best way to achieve this?
If I understood your main question (how to conditionally run a rule/rules using FluentValidation), you have a couple of options. In general, I'd recommend this nuget package (full disclosure, I wrote it), which helps keep things clean and also makes option 1 below a breeze.
Option 1: Run only relevant rules
Based on the value the user provided for has cat or not that you're binding to from your view, you could conditionally pull out the rules from the validator that exclude the rule(s) for that field:
In ViewModel:
var context = new ValidationContext<YourClass>(catInfoStuff);
if (doesNotHasCatLoL)
{
var descriptor = yourAbstractValidatorInstance.CreateDescriptor();
var scopedRules = new List<IValidationRule>();
foreach (var propName in listOfThePropertyNameStringsInYourClass)
scopedRules.AddRange(descriptor.GetRulesForMember(propName));
var fluentValidationResult = new ValidationResult(
scopedRules.SelectMany(x => x.Validate(context)).ToList());
}
else
{
var fluentValidationResult = yourAbstractValidatorInstance.Validate(context);
}
Option 2: Add a true/false flag to RootContextData for running the rule or not. e.g.:
In ViewModel:
var context = new ValidationContext<YourClass>(catInfoStuff);
context.RootContextData["HasCat"] = hasCatBindingValue; // from your view
In AbstractValidator:
RuleFor(catname => catname.CatName)
.Cascade(CascadeMode.StopOnFirstFailure)
.Custom((catname, context) =>
{
if (!context.ParentContext.RootContextData.ContainsKey("HasCat"))
{
// You may not want to flag this, as you'd likely have a separate rule for that on the other property
context.AddFailure("You need to indicate whether you have a cat or not...");
}
else
{
var hasCat = (bool)context.ParentContext.RootContextData["HasCat"];
if (hasCat && string.IsNullOrWhiteSpace(catname))
{
context.AddFailure("Please provide the name of your cat.");
}
// other checks, or just chain more below like you usually would since we StopOnFirstFailure
}
});
Here is an interesting requirement. How would I solve this with Breezejs?
(note, using a SPA design based on and extremely similar to the one in John Papa's Angular + Breezejs Pluralsight course)
We have a business rule that says that when I add or edit customer phone number, I need to check the phone number to see if there is a different customer with the same number (can happen due to phone number reassignment, etc).
If I find that it is a dup, I need to prompt the user. The user has the option to say "yah, that's fine", and then the phone number will save anyway.
So, I get how to do a basic validation with BeforeSaveEntity, and to fail if I find the dup, but suppose the user checks the "save anyway" option. How do I include this "out of band", non-data row information in my save set so that I can override the server-side validation rule?
And also, I don't want this validation to look like a "normal" error to the user on save -- I want to detect that it was the phone number clash thing, so I can display the view that prompts them to override.
Out of band data can be passed either by using the SaveOptions.tag property or by going to a separate named endpoint in your save call. i.e.
var so = new SaveOptions({ tag: "Special kind of save with extra data" });
return myEntityManager.saveChanges(null, so);
or
var so = new SaveOptions({ resourceName: "SaveWithSpecialValidation", tag: "any special data" });
return em.saveChanges(null, so);
In terms of how to return a special server side save validation
[HttpPost]
public SaveResult SaveWithSpecialValidation(JObject saveBundle) {
// custom tag passed from the client
var theTag = ContextProvider.SaveOptions.Tag;
ContextProvider.BeforeSaveEntitiesDelegate = BeforeSaveWithException;
return ContextProvider.SaveChanges(saveBundle);
}
private Dictionary<Type, List<EntityInfo>> BeforeSaveWithException(Dictionary<Type, List<EntityInfo>> saveMap) {
List<EntityInfo> orderInfos;
if (saveMap.TryGetValue(typeof(Order), out orderInfos)) {
if (YourErrorCheckHere(orderInfos)) {
var errors = orderInfos.Select(oi => {
return new EFEntityError(oi, "WrongMethod", "My custom exception message", "OrderID");
});
// This is a special exception that will be forwarded correctly back to the client.
var ex = new EntityErrorsException("test of custom exception message", errors);
// if you want to see a different error status code use this.
// ex.StatusCode = HttpStatusCode.Conflict; // Conflict = 409 ; default is Forbidden (403).
throw ex;
}
}
return saveMap;
}
Hope this makes sense. :)
i have developing project in c# for creating a user in AD.
i create a user and i want to create a attribute,like "mobilenumber"for this user.
when,i create this,the below error will occured.
here my code.
if (userDetails.GetUnderlyingObjectType() == typeof(DirectoryEntry))
{
dEntry = (DirectoryEntry)userDetails.GetUnderlyingObject();
if (User.UsrPassword != null && User.UsrPassword.Trim() != "")
{
if (dEntry.Properties.Contains("mobilenumber"))
{
Console.WriteLine("mobilenumberAttribute:Already created");
dEntry.Properties["mobilenumber"][0] = User.UsrPassword;
dEntry.CommitChanges();
}
else
{
Console.WriteLine("mobilenumber Attribute: Adding");
dEntry.Properties["mobilenumber"].Add(User.UsrPassword);
dEntry.CommitChanges();
}
userDetails.Save();
result = true;
}
}
The requested operation did not satisfy one or more constraints associated with the class of the object. (Exception from HRESULT: 0x80072014)
How can i resolve this?
Create an attribute? You mean like extending the schema? You can't do that by just adding it to an object. As you can see here, there is no such attribute as "mobilenumber". Maybe you want otherMobile (Phone-Mobile-Other) or mobile (Phone-Mobile-Primary)?
What are you trying to do? Why keep a copy of the password in the user object. If the user changes it, your copy will not be updated. If you need it to somehow inform the user, do something different like infoming his supervisor... Just a thought.
I have a gridview with three columns of textboxes. It can have as many rows as necessary but its usually only about 5 rows. Each row needs to be validated.
I want to create a client side validator that sums 2 of the columns together and compares it with the third column to check that the user has entered the data correctly.
Just in case you are wondering, it's part of the spec that the operator must enter the third column rather than simply summing the two previous columns together in the code behind. This is done to ensure the operator is transcribing the information correctly.
I am trying to use the custom validator in .net to create this client side validation. but I can't find a way to pass to it the names of the three text boxes.
I can give it the target controls name using the ControlToValidate parameter, but how do I pass in the other two control id's ?
I am looking for the 'proper' way to do this, one thought is to create an array in javascript referenced by the controltovalidate's name.
DC
I solved the problem. not an elegant solution but it works.
first I placed the code into a div on the page
<div align="right"><asp:CustomValidator ID="RowValidator" runat="server"
ErrorMessage="Total of #total# does not equal 1st Preference + Ticket"
ControlToValidate="Total" ValidateEmptyText="True"
ClientValidationFunction="CheckRow" SetFocusOnError="True" EnableClientScript="True"
enableViewState="False" Display="Dynamic"></asp:CustomValidator></div>
Then I created a JavaScript function...
function CheckRow(sender,args) {
// get the name of the control to validate
try {
args.IsValid = true;
ctv = sender.controltovalidate;
// get the data from the other controls
nt = document.getElementById(ctv.replace('_Total','_NonTicket'));
t = document.getElementById(ctv.replace('_Total','_Ticket'));
if (nt && t) {
v1 = Number(nt.value);
v2 = Number(t.value);
v3 = Number(args.Value);
if ((v1 + v2) != v3){
msg = GetMessage(sender);
sender.innerHTML = msg.replace("#total#",Number(args.Value));
args.IsValid = false;
return false;
}
}
}
catch (e) {
// something wrong default to server side validation
}
return true;
}
This is called by the custom validator for each row I use the controltovalidate parameter of the sender to get the name
then its a matter of a bit of string manipulation to get the names of the other fields.
Once retrieved you can do what you like, in my case I add and compare. if there is an error the Isvalid flag is cleared and the message is modified to suit.
The getmessage function is required because I alter the message to give a more meaningful error message
/*
get the error message from the validator
store it so it can be retrieved again
this is done because the message is altered
*/
function GetMessage(sender){
msg = window[sender.id+"_msg"];
if (!msg){
msg = sender.innerHTML;
window[sender.id+"_msg"] = msg;
}
return msg;
}
The getmessage function keeps a copy of the original message so if the user makes a mistake more than once the message can be retrieved in its pristine form, other wise the first time we edit a message we overwrite the placeholder (#total#).
DC