我想弄清楚如何在多個指令中保存和響應多個表單。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事件,但它是在現場驗證運行前右解僱,所以我不會得到該字段的當前錯誤狀態。
錯誤狀態必須從它應該向下傳遞到保存按鈕向上傳遞到主指令。
誰能幫助我得到的形式(甚至更好的相應字段)告訴主指令有一個無效的領域呢?
這真的很難例舉這樣一個複雜的任務,所以如果有任何含糊,請讓我知道。
非常感謝你提前。
朱利安