How to properly bind scope between directive and controller with angularJS

后端 未结 3 2012
耶瑟儿~
耶瑟儿~ 2021-02-02 13:32

I\'m trying to generate an n-level hierarchical unordered list with anugularJS, and have been able to successfully do so. But now, I\'m having scope issues between the directiv

3条回答
  •  死守一世寂寞
    2021-02-02 13:46

    Maxdec is right, this has to do with scoping. Unfortunately, this is a case that's complicated enough that the AngularJS docs can be mis-leading for a beginner (like myself).

    Warning: brace yourself for me being a little long-winded as I attempt to explain this. If you just want to see the code, go to this JSFiddle. I've also found the egghead.io videos invaluable in learning about AngularJS.

    Here's my understanding of the problem: you have a hierarchy of directives (navtree, navitem) and you want to pass information from the navitem "up the tree" to the root controller. AngularJS, like well-written Javascript in general, is set up to be strict about the scope of your variables, so that you don't accidentally mess up other scripts also running on the page.

    There's a special syntax (&) in Angular that lets you both create an isolate scope and call a function on the parent scope:

    // in your directive
    scope: {
       parentFunc: '&'
    }
    

    So far so good. Things get tricky when you have multiple levels of directives, because you essentially want to do the following:

    1. Have a function in the root controller that accepts a variable and update the model
    2. A mid-level directive
    3. A child-level directive that can communicate with the root controller

    The problem is, the child-level directive cannot see the root controller. My understanding is that you have to set up a "chain" in your directive structure that acts as follows:

    First: Have a function in your root controller that returns a function (which has reference to the root view controller's scope):

    $scope.selectFunctionRoot = function () {
        return function (ID) {
            $scope.itemselected = ID;
        }
    }
    

    Second: Set up the mid-level directive to have it's own select function (which it will pass to the child) that returns something like the following. Notice how we have to save off the scope of the mid-level directive, because when this code is actually executed, it will be in the context of the child-level directive:

    // in the link function of the mid-level directive. the 'navtreelist'
    scope.selectFunctionMid = function () {
        // if we don't capture our mid-level scope, then when we call the function in the navtreeNode it won't be able to find the mid-level-scope's functions            
        _scope = scope;
        return function (item_id) {
            console.log('mid');
            console.log(item_id);
    
            // this will be the "root" select function
            parentSelectFunction = _scope.selectFunction();
            parentSelectFunction(item_id);
        };
    };
    

    Third: In the child-level directive (navtreeNode) bind a function to ng-click that calls a local function, which will, in turn, "call up the chain" all the way to the root controller:

    // in 'navtreeNode' link function
    scope.childSelect = function (item_id) {
        console.log('child');
        console.log(item_id);
    
        // this will be the "mid" select function  
        parentSelectFunction = scope.selectFunction();
        parentSelectFunction(item_id);
    };
    

    Here's the updated fork of your JSFiddle, which has comments in the code.

提交回复
热议问题