import * as _ from "lodash"; import { ServiceError } from '../../entities/ServiceError'; import { ErrorScroll } from '../../util/ErrorScroll'; export function ServiceErrorDirectiveFactory() { return new ServiceErrorDirective(); } class ServiceErrorDirective implements ng.IDirective { restrict = 'A'; bindToController = true; controller = ServiceErrorController; controllerAs = 'ctrl'; // Service error attribute should be defined on the form itself require = 'form'; scope = { serviceError: '=' } link = (scope: ServiceErrorDirectiveScope, element: JQuery, attrs: ng.IAttributes, form: ng.IFormController) => scope.ctrl.form = form; } export class ServiceErrorController { // Both of these require setters: the service error injected value can change in the parent, // and the form is injected from the link function (after this controller constructor has already run) private _serviceError: ServiceError; private _form: angular.IFormController; constructor(private errorScroll: ErrorScroll) { } set form(form: angular.IFormController) { this._form = form; this.updateErrors(); } // This feels like it shouldn't be necessary, but because serviceError has two way binding, we need // to provide the original value back to the parent controller or it will be set to undefined get serviceError() { return this._serviceError; } set serviceError(serviceError: ServiceError) { this._serviceError = serviceError; this.updateErrors(); } private updateErrors() { if (this._form) { // First clean out the form in case service errors have been removed Object.keys(this._form) .filter(key => _.has(this._form, [key, 'serviceError'])) .forEach(key => delete (this._form[key] as ServiceErrorField).serviceError); // Now apply all the service errors to the correct fields if (this._serviceError && this._serviceError.errorList) { this._serviceError.errorList.forEach(value => { if (this._form[value.id]) { (this._form[value.id] as ServiceErrorField).serviceError = value.description; this._form[value.id].$setPristine(); } }); // Now scroll to the relevant error field this.errorScroll.scrollToError(this._form); } } } } interface ServiceErrorDirectiveScope extends angular.IScope { ctrl: ServiceErrorController; } export interface ServiceErrorField extends angular.INgModelController { serviceError: string }