角度指令+ $观察

时间:2013-10-14 15:20:13

标签: javascript angularjs

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

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”属性看似更新时,不会调用它。有人可以向我解释为什么这个例子不起作用吗?

3 个答案:

答案 0 :(得分:4)

对于具有独立范围的指令,您应用指令的元素不会继承父级的范围。因此,您不会看到任何{{src}}变量 - 它将始终为空。

使用隔离范围的指令属性,您可以通过两种方式与外部世界进行通信:

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

然后以下代码将起作用:

$attrs.$observe('src', function(value) {
  //some action
});

答案 1 :(得分:2)

我认为你有一些事情在进行,这总是有趣的调试。我怀疑$ 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 call,那么您可以更改您的html:

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

到:

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

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

答案 2 :(得分:1)

我认为你误用了$ 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, ...);

这样可以避免必须拆分指令中的值。