如何监听Formio ngFormBuilder自定义组件的添加与移除事件?
解决ng-formio-builder自定义组件添加/移除时的通知问题
我之前在使用ng-formio-builder时也碰到过类似的需求,针对v2.26.0版本的这个问题,分享几个可行的解决思路:
1. 深度监听form模型的components数组变化
组件的添加或移除本质上会修改builder绑定的form.components数组,我们可以通过Angular的$watch深度监听这个数组的变化,来判断是否有自定义组件被操作:
// 在你的builder所在控制器中添加监听 $scope.$watch('form.components', function(newComponents, oldComponents) { // 过滤出仅针对自定义组件的变化 const customComponentType = '你的自定义组件type值'; // 处理组件添加场景 if (newComponents.length > oldComponents.length) { const addedComp = newComponents.find(comp => !oldComponents.some(old => old.id === comp.id) && comp.type === customComponentType ); if (addedComp) { console.log('自定义组件已添加:', addedComp); // 这里触发你的业务通知逻辑 } } // 处理组件移除场景 else if (newComponents.length < oldComponents.length) { const removedComp = oldComponents.find(comp => !newComponents.some(new => new.id === comp.id) && comp.type === customComponentType ); if (removedComp) { console.log('自定义组件已移除:', removedComp); // 这里触发你的业务通知逻辑 } } }, true); // 第三个参数true开启深度监听,确保数组元素的变化能被捕获
这种方法不需要修改builder源码,兼容性较好,但如果表单组件数量较多,深度监听可能会有轻微性能损耗,可根据实际场景调整。
2. 在自定义组件内部触发全局事件
既然是针对自定义组件,我们可以直接在组件的控制器中,利用Angular的生命周期钩子来触发事件:
第一步:修改自定义组件的控制器
angular.module('你的模块名').controller('CustomComponentCtrl', function($scope, $rootScope) { // 组件被添加到builder时触发(控制器初始化时) $rootScope.$emit('customComponent:added', $scope.component); // 组件被从builder移除时触发(控制器销毁时) $scope.$on('$destroy', function() { $rootScope.$emit('customComponent:removed', $scope.component); }); });
第二步:在主控制器中监听事件
// 在你的业务控制器中监听全局事件 $rootScope.$on('customComponent:added', function(event, component) { // 处理组件添加后的逻辑 console.log('收到自定义组件添加通知:', component); }); $rootScope.$on('customComponent:removed', function(event, component) { // 处理组件移除后的逻辑 console.log('收到自定义组件移除通知:', component); });
这种方法精准性最高,只针对你的自定义组件生效,也不会影响其他组件的性能。
3. 装饰builder核心服务拦截操作
如果需要全局拦截所有组件的添加/移除操作,或者想更贴近builder的内部逻辑,可以通过Angular的$provide.decorator来重写builder的核心方法:
angular.module('你的模块名').config(function($provide) { $provide.decorator('builderService', function($delegate, $rootScope) { // 保存原始的addComponent方法 const originalAdd = $delegate.addComponent; // 重写addComponent方法 $delegate.addComponent = function(component, path) { const result = originalAdd.call(this, component, path); // 判断是否为自定义组件 if (component.type === '你的自定义组件type值') { $rootScope.$emit('customComponent:added', component); } return result; }; // 同样处理移除组件的方法 const originalRemove = $delegate.removeComponent; $delegate.removeComponent = function(path) { const targetComp = this.getComponent(path); const result = originalRemove.call(this, path); if (targetComp && targetComp.type === '你的自定义组件type值') { $rootScope.$emit('customComponent:removed', targetComp); } return result; }; return $delegate; }); });
这个方法需要你对ng-formio-builder的内部服务有一定了解,不过能最直接地拦截builder的核心操作,适合需要全局统一处理的场景。
注意事项
- 记得在不需要监听事件时,调用
$off解绑事件,避免内存泄漏; - v2.26.0版本的builder内部方法名可能和最新版有差异,若发现方法不匹配,可以查看源码确认具体的方法名称;
- 如果使用
$rootScope触发事件,尽量在事件名称前加上自定义前缀,避免和其他模块的事件冲突。
内容的提问来源于stack exchange,提问作者Ens
相关产品推荐
相关产品推荐

