2016-02-29 16 views
5

我想弄清楚如何在多個指令中保存和響應多個表單。Angular-Formly:與多個指令中的多個表單進行交互

爲了給你一個簡短的概述: Screenshot of the current view

我已經得到形式包含三個選項卡和第四含JsTree(組)。三個選項卡中的每一個都包含一個指令,該指令又包含一個Formly表單。 這些選項卡包含一個主指令,其中包含一個頁腳指令,右下角有保存和取消按鈕。

主要指令:

/** 
 
* 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>

頁腳指令

/** 
 
* 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>

第一個標籤的指令

/** 
 
* 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>

第二個嘗試:FormlyChangeService =>得到改變觸發的事件,但之前驗證=>沒有成功

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 } 
 

 
}

的Formly形式與餵養用戶模型,由主指令提供。

我必須在同一時間保存所有四個選項卡,因爲有必須存在保存輸入記錄幾個必填字段。 現在來棘手的部分:

我想保存按鈕被禁用,如果模型沒有改變或任何形式的任何領域發生錯誤。我也想知道錯誤來自哪種形式。

了我認爲的是在Formly場配置或類似事件或觀察者。

我試圖在球場上配置onChange事件,但它是在現場驗證運行前右解僱,所以我不會得到該字段的當前錯誤狀態。

錯誤狀態必須從它應該向下傳遞到保存按鈕向上傳遞到主指令。

誰能幫助我得到的形式(甚至更好的相應字段)告訴主指令有一個無效的領域呢?

這真的很難例舉這樣一個複雜的任務,所以如果有任何含糊,請讓我知道。

非常感謝你提前。

朱利安

回答

0

我想你應該有你的所有指令依賴於適用於所有形式的數據服務或工廠。

通過這種方式,您可以在指令中設置一個手錶,該手錶將調用共享服務上的任何方法來驗證/無效其他選項卡上的表單。

我希望這可以幫助