2016-02-29 11 views
5

sto cercando di capire come salvare e reagire su più moduli in più direttive.Angolare-Formalmente: interazione con più moduli in più direttive

Per darvi una breve panoramica: Screenshot of the current view

Ho tre schede che contengono forme e una quarta che contiene un JsTree (Gruppi). Ciascuna delle tre schede contiene una direttiva, che a sua volta contiene una forma Formly. Le schede sono racchiuse da una direttiva principale che contiene una direttiva footer con i pulsanti Salva e Annulla nell'angolo in basso a destra.

direttiva principale:

/** 
 
* Displays the ui for editing a specific user 
 
*/ 
 
export function UserDetailsDirective() { 
 
\t class UserDetailsDirective { 
 

 
\t \t /*@ngInject*/ 
 
\t \t constructor(
 
\t \t \t $stateParams, 
 
\t \t \t userService, 
 
\t \t \t formlyChangeService 
 
\t \t) { 
 
\t \t \t this.currentUser = this.currentUser || {}; 
 
\t \t \t this.originalUser = this.originalUser || {}; 
 

 
\t \t \t this.userForms = { 
 
\t \t \t \t mainData: {}, 
 
\t \t \t \t personalData: {}, 
 
\t \t \t \t basicSettings: {} 
 
\t \t \t }; 
 

 
\t \t \t this.savingAllowed = true; 
 
       
 
      /* Second try: Registering a callback at the change service, which will be executed on any field change in the passed form (mainData) */ 
 
      formlyChangeService.onFormChange('mainData',() => { 
 
\t \t \t \t console.log('test123'); 
 
\t \t \t \t console.log('this123', this); 
 

 
\t \t \t \t console.log('this.userForms.mainData.api.isValid()', this.userForms.mainData.api.isValid()); 
 
\t \t \t }); 
 

 

 
\t \t \t if ($stateParams.id > 0) { 
 
\t \t \t \t userService.getUser($stateParams.id).then((userData) => { 
 
\t \t \t \t \t userData.Birthday = new Date(userData.Birthday); 
 
\t \t \t \t \t this.currentUser = userData; 
 

 
\t \t \t \t \t this.breadcrumbData = [...]; 
 
\t \t \t \t }) 
 
\t \t \t } 
 
\t \t } 
 

 
\t \t onSave(controller) { 
 
\t \t \t alert('on save'); 
 
\t \t \t console.log('controller', controller); 
 
\t \t } 
 
\t } 
 

 
\t return { 
 
\t \t restrict: 'E', 
 
\t \t templateUrl: 'components/usermanagement/edit/user-details/user-details.directive.html', 
 
\t \t controller: UserDetailsDirective, 
 
\t \t controllerAs: 'controller', 
 
\t \t bindToController: true 
 
\t } 
 
}
<breadcrumb [...]></breadcrumb> 
 

 
<ul class="nav nav-tabs"> 
 
\t <li class="active"><a data-toggle="tab" data-target="#mainData">Account data</a></li> 
 
\t <li><a data-toggle="tab" data-target="#personalData">Personal data</a></li> 
 
\t <li><a data-toggle="tab" data-target="#basicSettings">Settings</a></li> 
 
\t <li><a data-toggle="tab" data-target="#userGroupAssignment">Groups</a></li> 
 
</ul> 
 

 
<div class="row"> 
 
\t <div class="col-lg-6"> 
 
\t \t <div class="tab-content"> 
 
\t \t \t <div id="mainData" class="tab-pane fade in active"> 
 
\t \t \t \t <main-data user="controller.currentUser"></main-data> 
 
\t \t \t </div> 
 
\t \t \t <div id="personalData" class="tab-pane fade"> 
 
\t \t \t \t <personal-data user="controller.currentUser"></personal-data> 
 
\t \t \t </div> 
 
\t \t \t <div id="basicSettings" class="tab-pane fade"> 
 
\t \t \t \t <basic-settings user="controller.currentUser"></basic-settings> 
 
\t \t \t </div> 
 
\t \t \t <div id="userGroupAssignment" class="tab-pane fade"> 
 
\t \t \t \t <group-assignment user="controller.currentUser"></group-assignment> 
 
\t \t \t </div> 
 
\t \t </div> 
 
\t </div> 
 
\t <div class="col-lg-6"> 
 
\t \t [...] <!-- Right column --> 
 
\t </div> 
 
</div> 
 

 
<!-- Footer --> 
 
<user-details-footer 
 
\t on-save="controller.onSave(controller)" 
 
\t saving-allowed="controller.savingAllowed" 
 
></user-details-footer>

direttiva Footer

/** 
 
* Displays the user details footer 
 
*/ 
 
export function UserDetailsFooterDirective() { 
 
\t class UserDetailsFooterDirective { 
 

 
\t \t /*@ngInject*/ 
 
\t \t constructor(
 
\t \t \t $state, 
 
\t \t \t Notification, 
 
\t \t \t $translate 
 
\t \t) { 
 
\t \t \t this.state = $state; 
 
\t \t \t this.notification = Notification; 
 
\t \t \t this.translate = $translate; 
 

 
\t \t \t this.savingAllowed = this.savingAllowed || false; 
 
\t \t } 
 

 
\t \t /** 
 
\t \t * Event that is triggered on save button click 
 
\t \t * 
 
\t \t * Propagates to the parent controller via attribute binding 
 
\t \t */ 
 
\t \t saveEvent() { 
 
\t \t \t if (typeof this.onSave === 'function') { 
 
\t \t \t \t this.onSave(); 
 
\t \t \t } 
 
\t \t } 
 

 
\t \t /** 
 
\t \t * Navigates to the user list 
 
\t \t */ 
 
\t \t goToUserList() { 
 
\t \t \t this.state.go('userList'); 
 
\t \t } 
 
\t } 
 

 
\t return { 
 
\t \t restrict: 'E', 
 
\t \t templateUrl: 'components/usermanagement/edit/user-details-footer/user-details-footer.directive.html', 
 
\t \t controller: UserDetailsFooterDirective, 
 
\t \t controllerAs: 'controller', 
 
\t \t bindToController: true, 
 
\t \t scope: { 
 
\t \t \t onSave: '&?', 
 
\t \t \t savingAllowed: '=?' 
 
\t \t } 
 
\t } 
 
}
<nav class="navbar navbar-fixed-bottom"> 
 
\t <div class="container-fluid pull-right"> 
 
\t \t <button class="btn btn-default" ng-click="controller.goToUserList()"><i class="fontIcon fontIconX"></i> Cancel</button> 
 
\t \t <button class="btn btn-primary" ng-disabled="controller.savingAllowed !== true" ng-click="controller.saveEvent()"><i class="fontIcon fontIconSave"></i> Save</button> 
 
\t </div> 
 
</nav>

direttiva

Prima della scheda

/** 
 
* Displays the contents of the tab "Account data" 
 
*/ 
 
export function MainDataDirective() { 
 
\t class MainDataDirective { 
 

 
\t \t /*@ngInject*/ 
 
\t \t constructor(
 
\t \t \t formlyFormService, 
 
\t \t \t mainDataFieldProviders, 
 
\t \t \t $state, 
 
\t \t \t userSubmitService, 
 
\t \t \t $timeout, 
 
\t \t  formlyChangeService, 
 
\t \t  $scope 
 
\t \t) { 
 
\t \t \t this.state = $state; 
 
\t \t \t this.$timeout = $timeout; 
 

 
\t \t \t this.userSubmitService = userSubmitService; 
 

 
\t \t \t this.model = {}; 
 
\t \t \t this.originalUser = this.originalUser || {}; 
 
\t \t \t this.fields = []; 
 

 
\t \t \t this.form = null; 
 
\t \t \t var that = this; 
 

 
      /* Third try: Watching the form instance => partial success */ 
 
\t \t \t this.watch('formMainData', function(x, y, form) { 
 
\t \t \t \t console.log('formMainData', form); 
 
\t \t \t \t that.form = form; 
 
\t \t \t \t form.watch('$invalid', function(foo, bar, value) { 
 
        /* This will react on field changes but it seems really dirty to me */ 
 
\t \t \t \t \t console.log('$invalid', arguments); 
 
\t \t \t \t }); 
 

 
\t \t \t }); 
 

 

 
\t \t \t formlyFormService.getFormConfiguration(mainDataFieldProviders).then((result) => { 
 
\t \t \t \t /* Here the formly fields are set */ 
 
       this.fields = result; 
 
       /* Second try: A service which provides a callback that will be executed on field invalidation => no success */ 
 
\t \t \t \t formlyChangeService.registerFields(this.fields, 'mainData'); 
 
\t \t \t }, (error) => { 
 
\t \t \t \t console.error('getMainDataFields error:', error); 
 
\t \t \t }); 
 

 
\t \t \t this.api = { 
 
\t \t \t \t isValid: angular.bind(this, this.isValid), 
 
\t \t \t \t submit: angular.bind(this, this.onSubmit) 
 
\t \t \t } 
 
\t \t } 
 

 
     /* First try to get the validity of the fields => no success */ 
 
\t \t isValid() { 
 
\t \t \t //return this.$timeout(() => { 
 
\t \t \t \t let isValid = true; 
 

 
\t \t \t \t this.fields.some((field) => { 
 
\t \t \t \t \t if (
 
\t \t \t \t \t \t field.validation.errorExistsAndShouldBeVisible === true 
 
\t \t \t \t \t \t || field.validation.serverMessages.length > 0 
 
\t \t \t \t \t) { 
 
\t \t \t \t \t \t isValid = false; 
 
\t \t \t \t \t \t return true; 
 
\t \t \t \t \t } 
 
\t \t \t \t }); 
 

 
\t \t \t \t //return isValid; 
 
\t \t \t //}, 10); 
 

 
      return isValid; 
 
\t \t } 
 

 
\t \t /** 
 
\t \t * Method triggered by the formSubmit event 
 
     */ 
 
\t \t onSubmit() { 
 
\t \t \t this.userSubmitService.submitUser(this.fields, this.model); 
 
\t \t } 
 
    } 
 

 
\t return { 
 
\t \t restrict: 'E', 
 
\t \t templateUrl: 'components/usermanagement/edit/main-data/main-data.directive.html', 
 
\t \t controller: MainDataDirective, 
 
\t \t controllerAs: 'controller', 
 
\t \t bindToController: true, 
 
\t \t scope: { 
 
\t \t \t originalUser: '=user', 
 
\t \t \t api: '=?' 
 
\t \t }, 
 
\t \t link: (scope) => { 
 
\t \t \t scope.$watch('controller.originalUser', (newValue) => { 
 
\t \t \t \t if (newValue.hasOwnProperty('ID')) { 
 
\t \t \t \t \t scope.controller.model = angular.copy(newValue); 
 
\t \t \t \t } 
 
\t \t \t }); 
 
\t \t } 
 
\t } 
 
}
<form name="controller.form" ng-submit="controller.onSubmit()" class="form-horizontal" novalidate> 
 
\t <formly-form form="controller.formMainData" model="controller.model" fields="controller.fields" ></formly-form> 
 
</form>

secondo tentativo: FormlyChangeService => ottenuto evento di modifica sparato ma prima della convalida => senza successo

export /*@ngInject*/ function FormlyChangeService() { 
 
\t let callbacks = []; 
 

 
\t return { 
 
\t \t triggerFormChangeEvent: triggerFormChangeEvent, 
 
\t \t registerFields: registerFields, 
 
\t \t onFormChange: onFormChange 
 
\t }; 
 

 
\t function triggerFormChangeEvent(value, options) { 
 
\t \t callbacks.forEach((callback) => { 
 
\t \t \t if (
 
\t \t \t \t typeof callback === 'function' 
 
\t \t \t \t && callback.formDirective === options.templateOptions.formDirective 
 
\t \t \t) { 
 
\t \t \t \t callback(); 
 
\t \t \t } 
 
\t \t }); 
 
\t } 
 

 
\t function onFormChange(formDirective, callback) { 
 
\t \t callback.formDirective = formDirective; 
 
\t \t callbacks.push(callback); 
 
\t } 
 

 
\t function registerField(fieldConfig) { 
 
\t \t fieldConfig.templateOptions.changeEvents.push(
 
\t \t \t triggerFormChangeEvent 
 
\t \t); 
 
\t } 
 

 
\t function registerFields(fieldConfigs, formDirective) { 
 
\t \t fieldConfigs.forEach((fieldConfig) => { 
 
\t \t \t fieldConfig.templateOptions.formDirective = formDirective; 
 
\t \t \t registerField(fieldConfig); 
 

 
\t \t \t fieldConfig.watcher = { 
 
\t \t \t \t listener: function() { 
 
\t \t \t \t \t console.log('listener', arguments); 
 
\t \t \t \t } 
 
\t \t \t }; 
 

 
\t \t \t console.log('fieldConfig', fieldConfig); 
 

 

 
\t \t \t fieldConfig.watch('$valid', function() { 
 
console.log('valid field', arguments); 
 
\t \t \t }); 
 

 

 

 

 
\t \t }); 
 
\t } 
 

 
}

Le forme formly sono alimentati con una modello utente, che è fornito dalla direttiva principale.

Devo salvare tutte e quattro le schede contemporaneamente perché ci sono diversi campi obbligatori che devono essere presenti per salvare il record inserito. Ora arriva la parte difficile:

Voglio che il pulsante di salvataggio sia disabilitato se il modello non è cambiato o si è verificato un errore in qualsiasi campo in qualsiasi forma. Voglio anche sapere da quale forma proviene l'errore.

Quello che ho pensato è un evento o un osservatore nella configurazione del campo Formalmente o qualcosa di simile.

Ho provato l'evento onChange sul campo config, ma è stato generato prima dell'esecuzione della convalida del campo, quindi non otterrò lo stato di errore corrente di quel campo.

Lo stato di errore deve essere passato alla direttiva principale da cui deve essere passato al pulsante Salva.

Qualcuno può aiutarmi a ottenere i moduli (o anche i rispettivi campi) per dire alla direttiva principale che esiste un campo non valido?

È davvero difficile esemplificare un compito così complesso, quindi se c'è qualche oscurità per favore fatemelo sapere.

Grazie mille in anticipo.

Julian

risposta

0

penso che si dovrebbe avere un servizio o di una fabbrica che tutti i vostri direttiva dipendono che contiene i dati di tutti i moduli.

In questo modo è possibile impostare un orologio nella direttiva che chiamerà qualsiasi metodo sul servizio condiviso per convalidare/invalidare i moduli nelle altre schede.

Spero che questo aiuti

Problemi correlati