简体   繁体   English

ngSrc更新了ngClick,但没有更新keydown事件处理程序

[英]ngSrc updates on ngClick, but not on keydown event handler

I am working on a live map type application that has some buttons to navigate (eg pan, zoom, etc.). 我正在开发一个实时地图类型的应用程序,它有一些导航按钮(例如平移,缩放等)。 I added a keydown event handler to allow keyboard control. 我添加了一个keydown事件处理程序以允许键盘控制。 The event handler calls the same method. 事件处理程序调用相同的方法。

I found it odd that the buttons are snappy and reliable in their response to load the image, but the keydown response is terribly slow. 我发现奇怪的是按钮在加载图像的响应中是活泼可靠的,但是keydown响应速度非常慢。 Now, I actually think the image update was due to the $interval service that was repeatedly fetching it and not from the keydown event at all. 现在,我实际上认为图像更新是由于$interval服务重复获取它而不是来自keydown事件。 Note: I already handle stale cached images (was a separate issue) by appending the url with a unique data like date/time. 注意:我已经通过在url附加日期/时间等唯一数据来处理过时的缓存图像(这是一个单独的问题)。

I added console logging to ensure that the imgUrl is actually changing, and it is. 我添加了控制台日志记录以确保imgUrl实际上正在发生变化,而且确实如此。 It seems that the button click is causing ngSrc to re-render with the updated imgUrl , but the keyboard event is not. 似乎按钮单击导致ngSrc使用更新的imgUrl重新渲染,但键盘事件不是。 Here is a simplified test app that recreates the same behavior with a button and the 't' key and in this case they keydown event: 这是一个简化的测试应用程序,它使用按钮和't'键重新创建相同的行为,在这种情况下,它们是keydown事件:

Plunker Plunker

javascript JavaScript的

var myApp = angular.module("myApp", ['ngMaterial'])
    .controller("myCtrl", function ($scope)
    {
        $scope.isToggled = false;

        $scope.Toggle = function ()
        {
            console.log("Toggle(Start): " + $scope.imgUrl);

            if ($scope.isToggled)
            {
                $scope.imgUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/7/74/Grassland_wiki.jpg/640px-Grassland_wiki.jpg";
            }
            else
            {
                $scope.imgUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/0/01/Monotropa_uniflora_03769.jpg/640px-Monotropa_uniflora_03769.jpg";
            }

            $scope.isToggled = !$scope.isToggled;

            console.log("Toggle(End): " + $scope.imgUrl);
        };

        $scope.ProcessKey = function (e)
        {
            if (e.key === "t")
            {
                $scope.Toggle();
            }
        };

        $scope.Toggle();
        document.addEventListener("keydown", $scope.ProcessKey);
    });

html HTML

<div ng-controller="myCtrl" ng-app="myApp">
    <md-button class="md-raised" ng-click="Toggle()">Toggle</md-button>
    <img id="testImg" ng-cloak ng-src="{{imgUrl}}">
</div>

I'm stumbling through javascript and angularjs in support of a C# application which is where most of my experience is. 我正在使用javascript和angularjs来支持C#应用程序,这是我的大部分经验。

I am not sure what the root cause is. 我不确定根本原因是什么。 Perhaps it is something to do with the javascript event listener referencing a $scope function variable/expression? 也许这与引用$scope函数变量/表达式的javascript事件监听器有关? Part of that dependency is that in my main app, I'm using the $http service to get the image. 部分依赖是在我的主应用程序中,我使用$http服务来获取图像。

Is there an alternative to the way I'm doing this? 有没有替代我这样做的方式? Is there a way to force the image to rerender? 有没有办法强迫图像重新渲染?

Because you adding an event outside AngularJS , Angular will never know that the $scope property changed. 因为您在AngularJS之外添加事件,所以Angular永远不会知道$scope属性已更改。 So you manually have to tell Angular something has changed using $scope.$apply() . 因此,您必须手动告诉Angular使用$scope.$apply()更改了某些内容$scope.$apply()

 var myApp = angular.module("myApp", []) .controller("myCtrl", function ($scope) { $scope.isToggled = false; $scope.Toggle = function () { console.log("Toggle(Start): " + $scope.imgUrl); if ($scope.isToggled) { $scope.imgUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/7/74/Grassland_wiki.jpg/640px-Grassland_wiki.jpg"; } else { $scope.imgUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/0/01/Monotropa_uniflora_03769.jpg/640px-Monotropa_uniflora_03769.jpg"; } $scope.isToggled = !$scope.isToggled; console.log("Toggle(End): " + $scope.imgUrl); }; $scope.ProcessKey = function (e) { if (e.key === "t") { $scope.Toggle(); $scope.$apply(); } }; $scope.Toggle(); document.addEventListener("keydown", $scope.ProcessKey); }); 
 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> <div ng-controller="myCtrl" ng-app="myApp"> <button class="md-raised" ng-click="Toggle()">Toggle</button> <img id="testImg" ng-cloak ng-src="{{imgUrl}}"> </div> 

You could use $scope.apply(handler) 你可以使用$scope.apply(handler)

$scope.apply(function () {
    // Angular is now aware that something might of changed
    $scope.changeThisForMe = true;
});

Note: I prefer the $scope.apply(); 注意:我更喜欢$scope.apply(); solutions because they do not require a site element to be in focus first. 解决方案,因为它们不需要首先关注网站元素。


Because I'm stubborn, I found another solution with the goal of staying in AngularJS and thought I would provide it for completeness. 因为我很顽固,我找到了另一个解决方案,目标是留在AngularJS,并认为我会提供完整性。

Based on the following post: AngularJS ng-keydown directive only working for <input> context? 基于以下帖子: AngularJS ng-keydown指令仅适用于<input>上下文?

I removed the following line from the javascript: 我从javascript中删除了以下行:

document.addEventListener("keydown", $scope.ProcessKey);

I made the following tweak to the html using ng-keydown which I previously could only get working on input tags. 我使用ng-keydown对html进行了以下调整,之前我只能使用输入标签。 I added tabindex which allows an item to be in focus and solves the input tags problem: 我添加了tabindex ,它允许项目处于焦点并解决输入标签问题:

<div ng-controller="myCtrl" ng-app="myApp" tabindex="0" ng-keydown="ProcessKey($event);">
    <md-button class="md-raised" ng-click="Toggle()">Toggle</md-button><br>
    <img id="testImg" ng-cloak ng-src="{{imgUrl}}">
</div>

Note that I could not get it to work on the body tag. 请注意,我无法让它在body标签上工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM