【问题标题】:AngularJS view not updating while model changed changed after clicking input fields for some time单击输入字段一段时间后,AngularJS视图未更新而模型更改更改
【发布时间】:2019-12-15 10:32:48
【问题描述】:

我为 PDF 生成做了一个 json 文件设计器。

如果您想查看完整的代码,请打开底部的 plunker 链接。

视图的行为与预期不符。在调试器中,当我在其 SVG 场景中拖动元素时,模型会立即更改。 输入没有改变。 但是,如果我在输入框之间单击,它会突然将视图更新为正确的值。

这是我在指令内的作用域变量中设置值的地方:

    function endDrag(evt) {
        if (selectedElement) {
            let selectedEntry = scope.data.templateData.find(function(entry) {
                return entry.name === selectedElement.getAttribute("data-entry-name");
            });

            if(selectedEntry){
                selectedEntry.x = parseInt(selectedElement.transform.baseVal.getItem(0).matrix.e / scope.data.pdfViwer.zoom);
                selectedEntry.y = parseInt(selectedElement.transform.baseVal.getItem(0).matrix.f / scope.data.pdfViwer.zoom);
            }
            selectedElement = null;
        }
    }

这是我在控制器中的数据对象:

    $scope.data = {
    name: "",
    type: [{name:'Text',value:'text'}, {name:'Image',value:'image'}, {name:'Line',value:'line'}],
    templateData: [{
        'type': {name:'Text',value:'text'},
        'name': 'test',
        'text': 'test3',
        'x': 100,
        'y': 100
    }],
    pdfViwer: {
        height: 2970,
        width: 2000,
        zoom: .3
    },
    output: {
        show:true
    }
}

那些是更新太晚的输入字段:

                    <div class="input-group mb-3">
                        <div class="input-group-prepend">
                            <span class="input-group-text">(X,Y)</span>
                        </div>
                        <input type="text" ng-model="entry.x" aria-label="x" ng-init="entry.x=data.pdfViwer.width / 2" class="form-control">
                        <input type="text" ng-model="entry.y" aria-label="y" ng-init="entry.y=data.pdfViwer.height / 2" class="form-control">
                    </div>

这是预览 SVG 中 svg 组的组标记:

<g ng-repeat="entry in getTemplateData()" class="draggable" data-entry-name="{{entry.name}}"
                    transform="translate({{entry.x * data.pdfViwer.zoom}} {{entry.y * data.pdfViwer.zoom}})" 
                    draggable="true">

它稍后更新输入字段的事实明显表明数据已正确传输到控制器。为什么右边的Form更新这么懒。 他们没有办法强制视图重新渲染吗?

非常感谢您提供的每一个有用的建议:/

https://plnkr.co/edit/UwbxV6eQ7YBWEtZAFkCj?p=preview

【问题讨论】:

    标签: javascript angularjs svg angularjs-directive ngdraggable


    【解决方案1】:

    你可以使用$scope.$apply()强制视图渲染

    $apply() 用于从 AngularJS 框架之外执行 AngularJS 中的表达式。 (例如来自浏览器 DOM 事件、setTimeout、XHR 或第三方库)。因为我们正在调用 AngularJS 框架,所以我们需要执行适当的异常处理范围生命周期,执行 watch。

    https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$apply

    还有一个$applyAsyc() 方法:

    将 $apply 的调用安排在以后发生。实际时间差因浏览器而异,但通常约为 10 毫秒。 这可用于将需要在同一摘要中评估的多个表达式排队。

    https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$applyAsync

    我玩弄了你的 plnker,看起来如果你把 scope.$apply(); 放在你的 endDrag() 函数的末尾,它就会按预期工作:

            function endDrag(evt) {
            if (selectedElement) {
                let selectedEntry = scope.data.templateData.find(function(entry) {
                    return entry.name === selectedElement.getAttribute("data-entry-name");
                });
    
                if(selectedEntry){
                    selectedEntry.x = parseInt(selectedElement.transform.baseVal.getItem(0).matrix.e / scope.data.pdfViwer.zoom);
                    selectedEntry.y = parseInt(selectedElement.transform.baseVal.getItem(0).matrix.f / scope.data.pdfViwer.zoom);
                }
                selectedElement = null;
            }
            scope.$apply();
        }
    

    这样做的原因是,您的拖动事件似乎与 Angular 的摘要循环无关,因此您需要手动调用它,以便 Angular 对更改采取行动。

    【讨论】:

    • 我对 $scope.$apply 和 $digest 仍然很陌生,但您的示例使其更加清晰。谢谢
    • 基本上,您在网格中单击的事件处理程序发生在 Angular 的知识之外,因此您需要手动调用 scope.$apply() 以便它将使用最新更新重新渲染模型.此外,这就是为什么(之前)在您单击输入框时它会更新,因为此时您触发了角度更新并且它赶上了对模型所做的更改。当你在 Angular 中做某事时,比如使用 ng-model,这会自动发生。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-25
    • 1970-01-01
    • 1970-01-01
    • 2014-02-13
    • 2013-12-02
    • 2012-09-23
    相关资源
    最近更新 更多