วิธีต้องการตัวควบคุมในคำสั่ง angularjs


86

ใครช่วยบอกวิธีรวมคอนโทรลเลอร์จากคำสั่งหนึ่งในคำสั่ง angularJS อื่น ตัวอย่างเช่นฉันมีรหัสต่อไปนี้

var app = angular.module('shop', []).
config(['$routeProvider', function ($routeProvider) {
    $routeProvider.when('/', {
        templateUrl: '/js/partials/home.html'
    })
        .when('/products', {
        controller: 'ProductsController',
        templateUrl: '/js/partials/products.html'
    })
        .when('/products/:productId', {
        controller: 'ProductController',
        templateUrl: '/js/partials/product.html'
    });
}]);

app.directive('mainCtrl', function () {
    return {
        controller: function ($scope) {}
    };
});

app.directive('addProduct', function () {
    return {
        restrict: 'C',
        require: '^mainCtrl',
        link: function (scope, lElement, attrs, mainCtrl) {
            //console.log(cartController);
        }
    };
});

โดยบัญชีทั้งหมดฉันควรจะสามารถเข้าถึงคอนโทรลเลอร์ในคำสั่ง addProduct ได้ แต่ฉันไม่ใช่ มีวิธีที่ดีกว่านี้หรือไม่?


5
requireทำให้แน่ใจว่ามีคำสั่งอื่นอยู่แล้วรวมถึงคอนโทรลเลอร์ด้วย ^requireตรวจสอบองค์ประกอบที่อยู่เหนือองค์ประกอบปัจจุบันนอกเหนือจากองค์ประกอบปัจจุบัน ดังนั้นคุณต้องใช้ทั้งสองคำสั่งร่วมกันเพื่อให้ได้ผล มิฉะนั้นให้กำหนดคอนโทรลเลอร์ด้วยapp.controllerจากนั้นใช้ในคำสั่งทั้งสอง ไม่ว่าจะด้วยวิธีใดคุณสามารถใส่สิ่งนี้ลงใน Plunker แบบง่ายพร้อมกับโค้ด HTML ของคุณได้หรือไม่?
Josh David Miller

คำตอบ:


187

ฉันโชคดีและตอบคำถามนี้ในความคิดเห็นของคำถาม แต่ฉันกำลังโพสต์คำตอบแบบเต็มเพื่อความสมบูรณ์และเพื่อให้เราสามารถทำเครื่องหมายคำถามนี้เป็น "ตอบแล้ว"


ขึ้นอยู่กับสิ่งที่คุณต้องการทำให้สำเร็จด้วยการแชร์คอนโทรลเลอร์ คุณสามารถแชร์คอนโทรลเลอร์เดียวกัน (แม้ว่าจะมีอินสแตนซ์ต่างกัน) หรือแชร์อินสแตนซ์คอนโทรลเลอร์เดียวกันก็ได้

แชร์คอนโทรลเลอร์

คำสั่งสองคำสั่งสามารถใช้คอนโทรลเลอร์เดียวกันได้โดยส่งผ่านวิธีการเดียวกันไปยังสองคำสั่งดังนี้:

app.controller( 'MyCtrl', function ( $scope ) {
  // do stuff...
});

app.directive( 'directiveOne', function () {
  return {
    controller: 'MyCtrl'
  };
});

app.directive( 'directiveTwo', function () {
  return {
    controller: 'MyCtrl'
  };
});

คำสั่งแต่ละคำสั่งจะได้รับอินสแตนซ์ของตัวควบคุม แต่จะช่วยให้คุณสามารถแชร์ตรรกะระหว่างส่วนประกอบต่างๆได้มากเท่าที่คุณต้องการ

ต้องการตัวควบคุม

หากคุณต้องการแชร์อินสแตนซ์เดียวกันของคอนโทรลเลอร์คุณก็ใช้requireไฟล์.

requireทำให้แน่ใจว่ามีคำสั่งอื่นจากนั้นรวมคอนโทรลเลอร์เป็นพารามิเตอร์ของฟังก์ชันลิงก์ ดังนั้นหากคุณมีคำสั่งสองคำสั่งในองค์ประกอบเดียวคำสั่งของคุณอาจต้องการการมีอยู่ของคำสั่งอื่นและเข้าถึงวิธีการควบคุมได้ ngModelกรณีการใช้งานทั่วไปสำหรับเรื่องนี้คือจะต้อง

^requireด้วยการเพิ่มเครื่องหมายคาเร็ตให้ตรวจสอบองค์ประกอบที่อยู่เหนือคำสั่งนอกเหนือจากองค์ประกอบปัจจุบันเพื่อค้นหาคำสั่งอื่น ๆ สิ่งนี้ช่วยให้คุณสามารถสร้างส่วนประกอบที่ซับซ้อนโดยที่ "ส่วนประกอบย่อย" สามารถสื่อสารกับองค์ประกอบหลักผ่านตัวควบคุมเพื่อให้ได้ผลที่ยอดเยี่ยม ตัวอย่างอาจรวมถึงแท็บที่แต่ละบานสามารถสื่อสารกับแท็บโดยรวมเพื่อจัดการการสลับ ชุดหีบเพลงสามารถมั่นใจได้ว่าเปิดครั้งละหนึ่งชุดเท่านั้น เป็นต้น

ไม่ว่าในกรณีใดคุณต้องใช้ทั้งสองคำสั่งร่วมกันเพื่อให้ได้ผล requireเป็นวิธีการสื่อสารระหว่างส่วนประกอบต่างๆ

ดูหน้าคำแนะนำของคำสั่งสำหรับข้อมูลเพิ่มเติม: http://docs.angularjs.org/guide/directive


4
เป็นไปได้หรือไม่ที่จะต้องใช้ตัวควบคุมคำสั่งพี่น้อง? โดยพื้นฐานแล้วฉันต้องแชร์อินสแตนซ์เดียวกันของตัวควบคุมหรือบริการระหว่างคำสั่งพี่น้อง (เช่นเดียวกับในพี่น้อง DOM ไม่ใช่ในองค์ประกอบ DOM เดียวกัน) ที่ทำซ้ำโดยใช้ ng-repeat ลองนึกภาพรายการที่ซ้ำกันแต่ละรายการมีคำสั่งที่ต้องการสถานะหรือตรรกะร่วมกันระหว่างรายการเหล่านี้
CMCDragonkai

2
@CMCDragonkai ไม่มีทางทำได้ แต่มีสองวิธีทั่วไปในการทำสิ่งเดียวกันให้สำเร็จ ประการแรกคือถ้าพี่น้องเป็น "ประเภท" เดียวกันองค์ประกอบที่อยู่เหนือ ngRepeat อาจเป็นเหมือนคำสั่งคอนเทนเนอร์และองค์ประกอบย่อยทั้งหมดสามารถต้องการคำสั่งนั้นแทนโดยทั้งหมดจะใช้คอนโทรลเลอร์เดียวกันร่วมกัน วิธีแก้ปัญหาทั่วไป - และมักจะเป็นที่ยอมรับมากขึ้นคือการใช้บริการที่ใช้ร่วมกัน คุณสามารถอธิบายรายละเอียดเกี่ยวกับสิ่งที่พี่น้องเหล่านี้ทำและสิ่งที่พวกเขาต้องการแบ่งปันได้หรือไม่?
Josh David Miller

ใช่จบลงด้วยการทำตัวเลือกแรก การใช้ตัวควบคุมคำสั่งคอนเทนเนอร์ ใช้งานได้ดี สำหรับการก่ออิฐ
CMCDragonkai

นี่เป็นคำตอบที่ดีและทำให้ฉันเข้าใจว่าทั้งหมดนี้ทำงานอย่างไร ขอบคุณ! (โปรดทราบว่านี่อาจเป็นคุณลักษณะที่ใหม่กว่า แต่คุณสามารถใช้requireเพื่อระบุคำสั่งเดียวหรืออาร์เรย์ของคำสั่งแต่ละคำสั่งสามารถนำหน้าด้วยเครื่องหมาย^
คาเร็ต

การใช้คอนโทรลเลอร์เดียวกันในสองคำสั่งไม่ได้ให้แต่ละคำสั่งเป็นอินสแตนซ์ของตัวเอง
jsbisht

27

มีคำตอบ stackoverflow ที่ดีที่นี่โดย Mark Rajcok:

AngularJS directive controllers ต้องการ parent directive controllers?

พร้อมลิงก์ไปยัง jsFiddle ที่ชัดเจนนี้: http://jsfiddle.net/mrajcok/StXFK/

<div ng-controller="MyCtrl">
    <div screen>
        <div component>
            <div widget>
                <button ng-click="widgetIt()">Woo Hoo</button>
            </div>
        </div>
    </div>
</div>

JavaScript

var myApp = angular.module('myApp',[])

.directive('screen', function() {
    return {
        scope: true,
        controller: function() {
            this.doSomethingScreeny = function() {
                alert("screeny!");
            }
        }
    }
})

.directive('component', function() {
    return {
        scope: true,
        require: '^screen',
        controller: function($scope) {
            this.componentFunction = function() {
                $scope.screenCtrl.doSomethingScreeny();
            }
        },
        link: function(scope, element, attrs, screenCtrl) {
            scope.screenCtrl = screenCtrl
        }
    }
})

.directive('widget', function() {
    return {
        scope: true,
        require: "^component",
        link: function(scope, element, attrs, componentCtrl) {
            scope.widgetIt = function() {
                componentCtrl.componentFunction();
            };
        }
    }
})


//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});

function MyCtrl($scope) {
    $scope.name = 'Superhero';
}

4
สำหรับฉันสิ่งที่ทำให้คลิกตัวอย่างของ Mark Rajcok มากที่สุดคือการให้ความสำคัญกับวิธีการสร้างวิธีการควบคุม โดยทั่วไปคุณจะเห็นเมธอดคอนโทรลเลอร์ที่สร้างผ่าน $ scope.methodName = function () {... } แต่เพื่อให้สามารถใช้งานได้คุณต้องใช้ this.methodName สำหรับวิธีการที่คุณต้องการให้เข้าถึง ตอนแรกฉันไม่ได้สังเกตว่า
coblr
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.