Widget Definitions

In this page you will find all the definitions of the parent class from which childs can inherit to become an ngSurvey widget.

class NGSWidget {
  static get type() {
    return "NGSWidget"
  }

  /* Html template that will generate before class gets created
     All id's and css classes name will be suffixed by the uniqueId
     provided during creation of the widget */
  static get template() {}

  /* Html template is used during design time of the form
     If null the actual widget template will be rendered */
  static get designTimeTemplate() {}

  /* Html template is when form is shown to be printed */
  static get printTemplate() {}

  /* Inline css style that will be added to the page
     note that style classes names will be scoped
     to the widget unique id 
  */
  static get style() {}

  /* Inline javascript code that will be added to 
     the page as long as the widget */
  static get script() {}

  static get selectionWidget() {
    return true;
  }

  /* Does this widget support label, the label is the text a form
  admin can enter using the form design and which will be displayed
  before the widget template */
  static get hasLabel() {
    return true;
  }

  /* Displays the ngsurvey native error message box 
     under the control
  */
  static get displayErrorMessage() {
    return true;
  }

  /* Will prefix all CSS classes from the widget style
     with a unique value to avoid conflicts if other components 
     have registered these classes under the same name.
     Note that it wont parse external CSS dependencies.
     0 : No encapsulation
     1 : Shadow CSS - native ngSurvey prefix processor
  */
  static get encapsulationMode() {
    return 1;
  }

  /* Allows the answer to be set required or not
   from the answer settings page to make
   the widget answer required during survey
  */
  static get required() {
    return false;
  }

  /* Properties that can be set in from the form designer for each
   answer using this widget as an answer type in the answer settings */
  static get propertiesDef() {}

  /* External javascript code dependencies that will be loaded
   before the widget gets created */
  static get jsDependencies() {}

  /* External css code dependencies that will be loaded
   before the widget gets created */
  static get cssDependencies() {}

  /*
    setAnswer; // callback furnction to post a value from the widget eg: answerPosted(widgetAnswerValue)
    valueChanges$; // Observable that returns the value of the widget
      containerElement;
      labelElement;
      respondentAnswers = [];
      uniqueId;
      answerContext;
      formContext;
      sectionIndex;
      properties;
      initialValue;
      label;
    */

  /* containerElement : DOM element holding the template
     labelElement: DOM element holding the label
     answerContext: Answer context that provides helper methods to interact with the answer
     formContext: Form context that provides helper methods to interact with the form
     uniqueId: must be used to query as suffix the template element id's or css classes
     properties : instance specific property values
     setAnswer: function that will set the given text value of the widget setAnswer(textVal) 
     valueChanges: monitor any value changes of the widget
     */
  constructor(containerElement, labelElement, answerContext, formContext,
    sectionIndex, uniqueId, properties, setAnswerCallback, valueChanges$) {
    this._value = null;
    this._subscribers = [];
    this.containerElement = containerElement;
    this.labelElement = labelElement;
    this.uniqueId = uniqueId;
    this.formContext = formContext;
    this.sectionIndex = sectionIndex;
    this.properties = properties;
    this.answerContext = answerContext;
    this.initialValue = answerContext.initialValue;
    this.valueChanges$ = valueChanges$;
    this.setAnswer = (value) => {
      // Keeps a local copy of the value being set
      this._value = value;

      setAnswerCallback(value);
    };

    this.getLabel$(label => {
      this.label = label;
    })

    this.getRespondentAnswers$(respondentAnswers => {
      this.respondentAnswers = respondentAnswers;
    });

    this.getAnswers$(answers => {
      this.answers = answers;
    });

    this.getQuestions$(questions => {
      this.questions = questions;
    });

  }

  /* Widget has been template has not yet been added to the DOM
     but its properties have been already been set 
  */
  build() {}

  /* Widget has been template has added to the DOM
     and its properties have been set 
  */
  init() {}

  /* Subscribe to the observable and keeps
     a reference to automatically unsubscribe
     it when the widget gets disposed
  */
  safeSubscribe(obs, next, error, complete) {
    // add to array
    if (obs) {
      this._subscribers.push(obs.subscribe(next, error, complete));
    }
  }

  // Beta Not for production
  remoteValidate() {
    var validationParams = [];
    for (var key in this.properties) {
      validationParams.push(this.getValidationParam(key, this.properties[key]));
    }
    validationParams.push(this.getValidationParam('secret', '6LeFY6QUAAAAAEwJvr1FYG16rVQpJJ1RQEGV19QM'));
    validationParams.push(this.getValidationParam('response', this._value));
    var remoteValidationParams = {
      validationParams
    }
    return this.formContext.answerService.validate(this.answerContext.answer.id, remoteValidationParams).subscribe(val => {
      console.log('validate')
    });
  }

  // Beta  Not for production
  remoteValidateProd() {
    var validationParams = [];
    validationParams.push(this.getValidationParam('secret', '6LeFY6QUAAAAAEwJvr1FYG16rVQpJJ1RQEGV19QM'));
    validationParams.push(this.getValidationParam('response', this._value));
    var remoteValidationParams = {
      validationParams
    }
    return this.formContext.answerService.validate(this.answerContext.answer.id, remoteValidationParams).subscribe(val => {
      console.log('validate')
    });
  }

  getValidationParam(name, value) {
    return {
      name,
      value
    }
  }

  /* 
    returns the properties of the widget 
    in the callback
  */
  getProperties$(propsCallback) {
    this.safeSubscribe(this.answerContext.propertie$, propsCallback, null, null)
  }

  getLabel$(labelCallback) {
    this.safeSubscribe(this.answerContext.label$, labelCallback, null, null)
  }

  getValue$(valueCallback) {
    this.safeSubscribe(this.valueChanges$, (value) => {
      // Callback only if value has changed
      if (value != this._value) {
        valueCallback(value);
      }
    }, null, null)
  }

  isDisabled$(stateCallback) {
    this.safeSubscribe(this.answerContext.disabled$, stateCallback, null, null)
  }

  isSelected$(selectionCallback) {
    this.safeSubscribe(this.answerContext.isSelected$, selectionCallback, null, null)
  }

  getRenderMode$(renderModeCallback) {
    this.safeSubscribe(this.answerContext.renderMode$, renderModeCallback, null, null)
  }

  getLanguage$(languageCallback) {
    this.safeSubscribe(this.formContext.language$, languageCallback, null, null)
  }

  getRespondentAnswers$(respondentAnswersCallBack) {
    this.safeSubscribe(this.formContext.respondentAnswers$, respondentAnswersCallBack, null, null)
  }

  getAnswers$(answersCallBack) {
    this.safeSubscribe(this.formContext.answers$, answersCallBack, null, null)
  }

  getQuestions$(questionsCallBack) {
    this.safeSubscribe(this.formContext.questions$, questionsCallBack, null, null)
  }

  /* Will be called by the form to see if the value is valid
     If not valid must return '' (no error message shown) or the error message to show
     If its valid return null */
  isValid() {
    return null;
  }

  /* Returns the html element from the dom that has been generated 
     from the widget template will match the suffixed ids of the 
     widget template
  */
  getWidgetElementById(id) {
    return this.widgetQuerySelector('#' + id);
  }

  /*
    Queryselector only on the container of the widget.
    Adds the widget unique id to ids (#) to match to 
    the suffixed local ids of the widget template 
  */
  widgetQuerySelector(selector) {
    // Suffix the id with the widget unique id 
    if (selector.indexOf('#') >= 0) {
      selector += this.uniqueId;
    }
    return this.containerElement.querySelector(selector);
  }

  /*
    QueryselectorAll only on the container of the widget.
    Adds the widget unique id to ids (#) to match to 
    the suffixed local ids of the widget template 
  */
  widgetQuerySelectorAll(selector) {
    // Suffix the id with the widget unique id 
    if (selector.indexOf('#') >= 0) {
      selector += this.uniqueId;
    }
    return this.containerElement.querySelectorAll(selector);
  }


  /* Cleans up all things that needs to be cleaned
     up before the widget gets destroyed from the dom */
  dispose() {}

  _disposeSubscribers() {
    if (this._subscribers) {
      this._subscribers.forEach(subscriber => {
        if (subscriber) {
          subscriber.unsubscribe();
        }
      })
      this._subscribers = [];
    }
  }

  /* Hooks the widget events to keep their 
    state in sync */
  _hookEvents() {}

  /* Internal method should not be overriden */
  _dispose() {
    this._disposeSubscribers();
    this.dispose();
  }

  /*  _value;
    _subscribers = [];*/
}

class NGSSelectionWidget extends NGSWidget {
  static get type() {
    return "NGSSelectionWidget"
  }
  /* containerElement : DOM element holding the template
     labelElement: DOM element holding the label
     answerContext: Answer context that provides helper methods to interact with the answer
     formContext: Form context that provides helper methods to interact with the form
     uniqueId: must be used to query as suffix the template element id's or css classes
     selectionId: is the unique id of the group of selection
     selectAnswerCallback: function that will be called when an answer must be selected from widget
     selected$: observable that returns true / false when answer is selected or unselected
     properties : instance specific property values
     setAnswer: function that will set the given text value of the widget setAnswer(textVal) */
  constructor(containerElement, labelElement, answerContext, formContext,
    sectionIndex, uniqueId, selectionId, selected, selectedAnswerCallback,
    selected$, properties, setAnswerCallback, valueChanges$) {
    super(containerElement, labelElement, answerContext,
      formContext, sectionIndex, uniqueId, properties, setAnswerCallback, valueChanges$)

    this.selectionId = selectionId;
    this.isSelected = selected;
    this.selected$ = selected$;

    this.selectAnswer = (selected) => {
      // If its a text answers save value locally  (eg: for "other" answers with fields and selections)
      if ((selected !== false && selected !== true) || selected == null || selected.length == 0) {
        this._value = selected;
      }
      selectedAnswerCallback(selected);
    };

    this.isSelected$(selected => {
      this.isSelected = selected;
    });
  }

  isSelected$(selectionCallback) {
    this.safeSubscribe(this.selected$, selectionCallback, null, null)
  }
}
export class AnswerContext {
  constructor(
    // Answer that is linked to that widget
    private answer: Answer,
    // Custom user defined properties that have been set for this widget  
    private propertie$: Observable<any>,
    // Current rendering mode of the widget eg: DesignTime (design), Standard (running)
    private renderMode$: BehaviorSubject<ControlRenderMode>,
    // Should the widget be disabled ?
    private disabled$: BehaviorSubject<boolean>,
    // Is the label enabled
    private showLabel: boolean,
    // Angular form control holding the value of the a
    private formControl: FormControl,
    // Inital value of the answer, could be the default value set 
    // by the survey admin or the previous respondent answer if the survey
    // is being resumed by the respondent
    private initialValue: string,
    // Label text of the answer, observable will stream the new value
    // if value changes in multi languages survey
    private label$: Observable<string>) { }
}
export class FormContext {
  constructor(
    // Actual respondent of the survey
    private respondent$: Observable<Respondent>,
    // Actual respondent answers of the survey, observable 
    // will stream any new answer update in realtime
    private respondentAnswers$: Observable<RespondentAnswer[]>,    
    // Survey answers
    private answers$: Observable<Answer[]>,
    // Survey questions
    private questions$: Observable<Question[]>,
    // Actual respondent language in multilanguage surveys
    private language$: Observable<Language>,
    // Helper method to access the angular http client
    private httpClient: HttpClient,
    // internal ngSurvey answer http services
    private answerService: AnswerService) { }
}

Last updated

(c) 2024 Data Illusion Zumbrunn. All rights reserved. Reproduction strictly forbidden.