1

I am trying to write a TypeScript/React class that will only get instantiated once and is accessible globally. The reason for this is a SharePoint CSR script. I load this script for New/Edit/Display forms and in my list, I have different content types. One of those content types is a child of another content type and I have written a react component that renders a few buttons in the NewForm of the parent content type so I can create child items from inside the NewForm. So far so good, but my CSR script gets instantiated every time a Form opens, meaning it will get instantiated for both my parent content type and child content type.

This is where my problem lies. I need to remove a few items from a drop down in the child content type's NewForm based on a value of another drop down in the parent NewForm. But because my script gets instantiated for both forms, the values I set in my validation class aren't in sync.

Here is my code:

class MyCsrScript{
   private validator: Validator;
   constructor(){
      this.validator = new Validator();
   }

   protected getTemplates(): SPClientTemplates.TemplateOverrides {
      let templates: SPClientTemplates.TemplateOverrides = {};

      templates.Fields = {
         "ParentDropDown": {
            NewForm: this.attachValidator,
            EditForm: this.attachValidator
      }
   }

   protected postRender(ctx: SPClientTemplates.RenderContext) {
      let fCtx = ctx as SPClientTemplates.RenderContext_FieldInForm;
      let field = fCtx.ListSchema.Field[0];
      if(field.Name === "ChildDropDown"){
         this.validator.setChildDD($("#" + field.Name + "_" + field.Id + "_\\$DropDownChoice"));    
         this.validator.validate();            
      }
   }

   private attachValidator(ctx: SPClientTemplates.RenderContext_FieldInForm) {
      let formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);
      formCtx.registerInitCallback(formCtx.fieldName, function(){
         let initialValue = getInitialValue(); //this will have a value for EditForm.aspx. For NewForm.aspx, it will be ""
         <ParentDropDown initialvalue = {initialValue} onChange={this.parentDDChange.bind(this)} />
         validator.setParentDropDownValue(initialValue);
      }
   }

   private parentDDChange(lookupValue: string) {
      this.validator.setParentDropDownValue(lookupValue);
      this.validator.validate();
   }
}

export class Validator{
   constructor(){  }

   public setChildDD(dropdown: JQuery){
      //Set child drop down
   }

   public setParentDropDownValue(value: string){
      //set value of parent drop down
   }

   public validate(){
      //remove options from child drop down depending on parent drop down value here...
   }
}

Basically, validator will get instantiated once when attachValidator is fired and once when postRender is fired. The second instance won't have the parent drop down's value. I already tried implementing a singleton pattern, but I got the same results here. So does anybody know how to solve this?

To clarify, I have added a little diagram:

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.