0

[UPDATE] It turns out that if I use "@" as scope variable, it will be used in a async way when render template( I still can not figure out why and how ), the order will be compiple -> controller -> pre ->post ->observe, the strange thing is until POST stage, the scope.data still object, but inside the observe, it suddenly become string, could any one give me some help about why this happen( like when the template get data bind to it)?

var app = angular.module("vp", []);
app
.controller("main", function($scope){
    $scope.data = ["1", "2"];
})
.directive("chartBuilder", function(){
    return {
        restrict: "AE",
        scope: {
            data: "@data"
        },
        controller: function($scope){
            console.log($scope.data);
            $scope.data = JSON.parse($scope.data);
        },
        template: '<div><input ng-repeat="d in data track by $index" ng-model="data[$index]" /></div>',
        compile: function(EL, attrs){
            console.log(EL);
            return {                    
                pre: function(scope, EL, attrs){
                    console.log(scope.data);
                },
                post: function(scope, EL, attrs){
                // link: function(scope, EL, attrs){
                    console.log(scope.data);
                    attrs.$observe("data", function(d){
                        console.log(d);
                        scope.data = JSON.parse(scope.data);
                        console.log(d);
                    })
                }
            }
        }
    };
});

All:

I am pretty new to Angular directive, say I have a directive which accept attr from parent scope:

<html ng-app="vp">
<head>
    <title></title>
</head>
<body ng-controller="main">

    <input ng-repeat="d in data track by $index" ng-model="data[$index]" />

    <chart-builder data={{data}}></chart-builder>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
    <script type="text/javascript">
        var app = angular.module("vp", []);
        app
        .controller("main", function($scope){
            $scope.data = ["1", "2"];
        })
        .directive("chartBuilder", function(){
            return {
                restrict: "AE",
                scope: {
                    data: "@"
                },
                controller: function($scope){
                    $scope.data = JSON.parse($scope.data);
                },
                template: '<div><input ng-repeat="d in data track by $index" ng-model="data[$index]" /></div>',
                link: function(scope, EL, attrs){
                }
            };
        });
    </script>

</body>
</html>

Notice that I use "@" in directive, the reason is I want to set logic like:

The parent scope can affect the value in directive, but in directive, it is only allowed to copy the data from parent scope and any change inside it can not reflect to parent scope.

So for example, the init parent scope data is [1,2], so the directive will get that as string(because @), and in controller, turn it into object, then render on the template.

But the thing is:

The data in directive is still a string when rendered on template, I wonder why the JSON.parse not work( in the controller of directive, It does work, but when bind to template, it still string )

Thanks

2
  • Try the parse in the link file, or even in the data={{JSON.parse...}} Commented Jan 21, 2016 at 18:35
  • @SimonH Thanks I tried both, but not work. And I thought the controller will run first, so I decide to move converting there which still not work. Could you show me what it looks like on your side? Commented Jan 21, 2016 at 18:38

1 Answer 1

1

Much simpler to just pass in the array reference:

<chart-builder data="data"></chart-builder>

JS

 app
    .controller("main", function($scope){
        $scope.data = ["1", "2"];
    })
    .directive("chartBuilder", function(){
        return {
            restrict: "AE",
            scope: {
                data: "="
            },
            controller: function($scope){
                console.log($scope.data)// array not string ["1", "2"]  
            },
            template: '...',
            link: function(scope, EL, attrs){
            }
        };
    });
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks, could you tell me why this code can prevent directive scope change affect parent scope data? I tried this but the parent scope change as well
Thanks, but could you show me how to use angular.copy(data) in my example, I tried but not work!
$scope.directiveData = angular.copy($scope.data) then <chart-builder data="directiveData ">
Thanks, I use <chart-builder data="angular.copy(data)"> but with no luck, I wonder why this is different as yours, and in your way, does it mean I have to manually monitoring data change and give it to directivedata?
because you can't use methods in view that aren't in controller scope. The view doesn't have global window variable access ... only what controllers and directives expose in models
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.