Angular 4 Input Directive:如何在表单提交时触发指令事件移除格式?
当然可以实现!而且有几种不同的方式来处理这个需求,我来给你详细拆解一下:
核心思路
你的本质需求是:视图层显示哥伦比亚格式的字符串,模型层保存原始数值,提交时确保模型里是未格式化的原始值。我们可以从「指令内部集成双向转换」和「提交时手动触发转换」两个方向来实现。
方法一:利用 ngModel 自动处理(推荐)
这是最符合Angular双向绑定设计的方案——让指令自动在视图和模型之间做转换,提交时模型已经是原始数值,无需额外操作。
指令实现示例
angular.module('yourApp').directive('colombianNumber', function() { return { require: 'ngModel', link: function(scope, element, attrs, ngModel) { // 1. 模型 → 视图:把原始数值转成哥伦比亚格式 ngModel.$formatters.push(function(rawValue) { if (!angular.isNumber(rawValue)) return ''; // 拆分整数和小数部分,添加千分位点,替换小数分隔符为逗号 const [integerPart, decimalPart] = rawValue.toString().split('.'); const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, '.'); const formattedDecimal = decimalPart ? `,${decimalPart.slice(0, 2)}` : ''; return formattedInteger + formattedDecimal; }); // 2. 视图 → 模型:把格式化字符串转成原始数值 ngModel.$parsers.push(function(formattedValue) { if (!formattedValue) return null; // 移除千分位点,把逗号换回点,转成浮点数 return parseFloat(formattedValue.replace(/\./g, '').replace(',', '.')) || null; }); // 3. 实时输入时维护光标位置(优化用户体验) element.on('input', function() { const cursorPos = element[0].selectionStart; const originalLength = element.val().length; // 触发ngModel的转换逻辑,更新视图 ngModel.$setViewValue(element.val()); scope.$apply(); // 调整光标位置,避免输入时光标跳到末尾 const newLength = element.val().length; element[0].selectionStart = element[0].selectionEnd = cursorPos + (newLength - originalLength); }); } }; });
使用方式
<form ng-submit="handleSubmit()"> <input type="text" colombian-number ng-model="transaction.amount"> <button type="submit">提交</button> </form>
提交逻辑
$scope.handleSubmit = function() { // 直接用模型值即可,它已经是原始数值(比如1000.25) console.log($scope.transaction.amount); // 这里写你的提交逻辑 };
方法二:提交时手动触发指令内的转换
如果你不想改动现有指令的实时格式化逻辑,也可以在指令中暴露一个「反格式化」方法,在提交时手动调用它来更新模型。
修改现有指令
angular.module('yourApp').directive('colombianNumber', function() { return { require: 'ngModel', link: function(scope, element, attrs, ngModel) { // 你的现有格式化逻辑(onKeyPress处理) element.on('keypress', function(e) { // 这里保留你原来的实时格式化代码 const currentValue = element.val(); // 你的格式化处理... element.val(yourFormatFunction(currentValue)); }); // 定义反格式化函数 function unformatValue(formattedStr) { if (!formattedStr) return null; return parseFloat(formattedStr.replace(/\./g, '').replace(',', '.')) || null; } // 把方法暴露给DOM元素,方便外部调用 element[0].syncRawValue = function() { const formatted = element.val(); const rawValue = unformatValue(formatted); ngModel.$setViewValue(rawValue); scope.$apply(); // 通知Angular更新模型 }; } }; });
提交时调用
<input type="text" colombian-number ng-model="transaction.amount" id="amountInput"> <button ng-click="handleSubmit()">提交</button>
$scope.handleSubmit = function() { // 获取输入元素,调用指令暴露的方法 const inputEl = document.getElementById('amountInput'); inputEl.syncRawValue(); // 现在模型里就是原始数值了 console.log($scope.transaction.amount); // 执行提交逻辑 };
额外优化建议
- 如果是表单提交,也可以在指令里监听表单的
submit事件,自动触发转换,无需在控制器里写额外代码:// 在指令link函数末尾添加 const form = element.closest('form'); if (form) { form.addEventListener('submit', function() { element[0].syncRawValue(); scope.$apply(); }); } - 实时格式化时一定要处理光标位置,不然用户输入体验会很差,方法一里已经包含了这个逻辑。
内容的提问来源于stack exchange,提问作者Vaxes
相关产品推荐
相关产品推荐

