1

我似乎误解了 $observe 的工作原理。从以下示例(plunker 链接)。

HTML

<html ng-app="record">

  <head>
    <script data-require="angular.js@*" data-semver="1.2.0-rc2" src="http://code.angularjs.org/1.2.0-rc.2/angular.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-controller="IndexController">
  <input type="text" value="{{src}}"/>
  <input type="text" value="{{RecordAddress}}"/>
  <input type="text" value="{{FlashVars}}"/>
  <input type="button" ng-click="handleClick()" value="click me"/>
    <record src="{{src}}"></record>
  </body>

</html>

JS

angular.module('record',[])
.controller("IndexController", function($scope)
{
  console.log('controller called')
  $scope.handleClick = function()
  {
    console.log('handleClick - called');
    $scope.RecordAddress = 'rtmp://thisIsAnAddress';
    $scope.FlashVars = 'userid=SomeId&filename=http://localhost/Content/ThisIsAnAddress/player.swf&mediaFormat=_video.mp4&mediaServerAddress=rtmp://ThisIsAnAddress&culture=en-GB'
    $scope.src = $scope.RecordAddress+ '`' + $scope.FlashVars;
  }
})
.directive('record', function ($location) {
            return {
                restrict: 'E',
                scope: {
                    current: '=current'
                },
                link: function ($scope, element, attr) {
                    console.log('record directive - called');
                    console.log(attr);

                    attr.$observe('src', function(value)
                        {
                            console.log('record observe callback called!');
                            console.log('The value is: '+ value);
                            if(value && value !='recordValues')
                            {
                                var values = value.split('`');
                                console.log('video values:')
                                console.log(values);
                                element.html('<object position="relative" width="519px" height="520px" data="'+values[0]+'" type="application/x-shockwave-flash"><param name="FlashVars" value="'+values[1]+'" /><param name="AllowScriptAccess" value="always" /></object>');
                            }
                            else
                            {
                                element.html("<div>Please wait</div>")
                            }
                        }
                    );
                }
            }
        });

我希望在单击按钮时呈现“对象”,而不是在设置未准备好时出现的“请稍候”。但是,当“src”属性看似更新时,它不会被调用。有人可以向我解释为什么这个例子不起作用吗?

4

3 回答 3

5

对于具有隔离范围的指令,您应用指令的元素不会继承父级的范围。所以你不会{{src}}在那里看到任何变量——它总是空的。

有两种方法可以使用具有隔离范围的指令的属性与外部世界进行通信:

  • 使用src="{{$parent.src}}",但它有点hackish
  • 使用@属性映射进行单向绑定
scope: {
    src: '@src'
}

然后以下代码将起作用:

$attrs.$observe('src', function(value) {
  //some action
});
于 2013-10-14T19:21:31.543 回答
3

我认为您同时进行了一些事情,这总是使调试变得有趣。我怀疑 $watch 可能更适合你。而且,使用element.html()调用会覆盖您尝试查看的 html 中的变量。

我做了一些更改(全部包含在您的指令中)并在下面有一些工作代码(我在其中添加了一个模板来放置您的消息-当然还有很多其他方法可以做同样的事情)。

directive('record', function ($location,$sce) {
        return {
            restrict: 'E',
            template: '<div ng-bind-html="trustedMsg"></div>',
            link: function ($scope, element, attr) {
                console.log('record directive - called');
                console.log(attr);

                $scope.$watch('src', function(value)
                    {
                        console.log('record observe callback called!');
                        console.log('The value is: '+ value);
                        if(value && value !='recordValues')
                        {
                            var values = value.split('`');
                            console.log('video values:')
                            console.log(values);
                            $scope.message='<object position="relative" width="519px" height="520px" data="'+values[0]+'" type="application/x-shockwave-flash"><param name="FlashVars" value="'+values[1]+'" /><param name="AllowScriptAccess" value="always" /></object>';
                            $scope.trustedMsg = $sce.trustAsHtml($scope.message);
                        }
                        else
                        {
                            $scope.message="<div>Please wait</div>";
                            $scope.trustedMsg = $sce.trustAsHtml($scope.message);
                        }
                    }
                );
            }
        }
    });

此外,如果您更喜欢使用 attr.$observe 调用,那么您可以将 html 从以下位置更改:

<record src='{{src}}'></record> 

到:

<record src='src'></record>

编辑:我更新(并测试)了代码,因此消息现在支持 html,就像您的代码一样。( http://plnkr.co/edit/K18Djio1NfSaHIWOXpeJ )

于 2013-10-14T16:42:13.963 回答
2

我认为您在滥用 $observe 功能,尽管我可能无法 100% 理解您正在尝试做的事情。我认为做你想做的更好的方法是在你的控制器中设置正确的src$scope,然后$watch用来检测该值的变化。以下是我建议您这样做的方法:

在您的控制器中:

$scope.handleClick = function(){
    console.log('handleClick - called');
    $scope.RecordAddress = 'rtmp://thisIsAnAddress';
    $scope.FlashVars = 'userid=SomeId&filena...';

    //Now set the src on the scope as you already had:
    $scope.source = $scope.RecordAddress+ '`' + $scope.FlashVars;
}

在您的 html 视图中:

<!-- remove the binding braces so you're just passing a regular attribute -->
<record src="source"></record>

在您的指令中:

//add a simple update function (for cleanliness)
function update(value){
    if(value && value !='recordValues'){
        var values = value.split('`');
        element.html('INSERT YOUR LONG HTML STRING HERE');
    }else{
        element.html("<div>Please wait</div>")
    }
}

// get any initial value for the 'source' variable
var value = scope.$eval(attrs.src);   // this will return the scope's source variable
if(value) update(value);

// watch for any changes to that variable on the scope
scope.$watch(attrs.src, update);

注意:尽管我相信上面的代码可以满足您的需求,但我认为这并不是最好的方法。您实际上是从控制器将两个值传递给您的指令: 1)RecordAddress和 2) FlashVars。我建议您为record元素添加两个单独的属性:

<record address="addr" flash-vars="flashVars"></record>

然后您将与您的指令分开绑定它们:

function update(addr, flashVars){ ... }

scope.$eval(addrs.address, function(value){ ... });
scope.$eval(addrs.flashVars, function(value){ ... });

scope.$watch(addrs.address, ...);
scope.$watch(addrs.flashVars, ...);

这将使您不必拆分指令中的值。

于 2013-10-14T16:34:31.320 回答