การสูญเสียขอบเขตเมื่อใช้ ng-include


181

ฉันมีเส้นทางโมดูลนี้:

var mainModule = angular.module('lpConnect', []).
    config(['$routeProvider', function ($routeProvider) {
    $routeProvider.
        when('/home', {template:'views/home.html', controller:HomeCtrl}).
        when('/admin', {template:'views/admin.html', controller:AdminCtrl}).
        otherwise({redirectTo:'/connect'});
}]);

โฮม HTML:

<div ng-include src="views.partial1"></div>

partial1 HTML:

<form ng-submit="addLine()">
    <input type="text" ng-model="lineText" size="30" placeholder="Type your message here">
</form>

HomeCtrl:

function HomeCtrl($scope, $location, $window, $http, Common) {
    ...
    $scope.views = {
        partial1:"views/partial1.html"
    };

    $scope.addLine = function () {
        $scope.chat.addLine($scope.lineText);
        $scope.lines.push({text:$scope.lineText});
        $scope.lineText = "";
    };
...
}

ในaddLineฟังก์ชั่น$scope.lineTextเป็นundefinedนี้สามารถแก้ไขได้โดยการเพิ่มng-controller="HomeCtrl"การpartial1.htmlอย่างไรจะทำให้การควบคุมจะถูกเรียกว่าเป็นครั้งที่สอง ฉันหายไปนี่อะไร

คำตอบ:


83

นี่เป็นเพราะng-includeสิ่งที่สร้างขอบเขตลูกใหม่ดังนั้นจึง$scope.lineTextไม่มีการเปลี่ยนแปลง ฉันคิดว่านั่นthisหมายถึงขอบเขตปัจจุบันดังนั้นthis.lineTextควรตั้งค่า


260

ตามที่ @Renan กล่าวไว้ ng-include จะสร้างขอบเขตลูกใหม่ ขอบเขตต้นแบบนี้สืบทอด (ดูเส้นประด้านล่าง) จากขอบเขต HomeCtrl ng-model="lineText"จริง ๆ แล้วสร้างคุณสมบัติขอบเขตดั้งเดิมบนขอบเขตลูกไม่ใช่ขอบเขตของ HomeCtrl ขอบเขตลูกนี้ไม่สามารถเข้าถึงขอบเขต parent / HomeCtrl:

ขอบเขตรวม ng

ในการจัดเก็บสิ่งที่ผู้ใช้พิมพ์ลงในอาร์เรย์ $ scope.lines ของ HomeCtrl ฉันขอแนะนำให้คุณส่งค่าไปยังฟังก์ชัน addLine:

 <form ng-submit="addLine(lineText)">

นอกจากนี้เนื่องจาก lineText เป็นเจ้าของโดยขอบเขต ngInclude / บางส่วนฉันรู้สึกว่ามันควรจะรับผิดชอบในการล้างมัน:

 <form ng-submit="addLine(lineText); lineText=''">

ฟังก์ชั่น addLine () จะกลายเป็น:

$scope.addLine = function(lineText) {
    $scope.chat.addLine(lineText);
    $scope.lines.push({
        text: lineText
    });
};

ซอ

ทางเลือก:

  • กำหนดคุณสมบัติวัตถุในขอบเขต $ ของ HomeCtrl และใช้สิ่งนั้นในบางส่วน: ng-model="someObj.lineText; ซอ
  • ไม่แนะนำนี้เป็นมากกว่าสับใช้งาน: ใช้ $ ผู้ปกครองบางส่วนในการสร้าง / การเข้าถึงlineTextทรัพย์สินใน HomeCtrl $ ขอบเขต:   ng-model="$parent.lineText"; ซอ

มันมีส่วนเกี่ยวข้องเล็กน้อยในการอธิบายว่าทำไมตัวเลือกทั้งสองข้างต้นถึงได้ผล แต่ก็อธิบายได้อย่างสมบูรณ์ที่นี่: อะไรคือความแตกต่างของขอบเขตมรดก / ต้นแบบต้นแบบใน AngularJS?

ฉันไม่แนะนำให้ใช้thisในฟังก์ชั่น addLine () มันมีความชัดเจนน้อยลงว่าขอบเขตใดที่ถูกเข้าถึง / จัดการ


1
ในที่สุดฉันก็เข้าใจ
Scott Tesler

1
มีคำถามเดียวกัน @Jess ทำไมจึงถูกพิจารณาว่าเป็นการแฮก
qbert65536

13
@ qbert65536 เป็นหลักแฮ็ค / เปราะบางเพราะถ้าคุณปรับโครงสร้าง HTML ของคุณก็อาจไม่ทำงานอีกต่อไป เช่นคุณอาจต้องใช้$parent.$parent...เพื่อให้มันทำงาน อีกวิธีหนึ่งโดยใช้$parentสร้างสมมติฐานเกี่ยวกับโครงสร้าง DOM
Mark Rajcok

6
การเชื่อมโยง @Jess' เหนือได้ถูกเปลี่ยนไปนี้การทำความเข้าใจขอบเขต ngInclude อ่านทั้งหน้ามันยอดเยี่ยมมาก
mraaroncruz

1
นี่เป็นคำตอบที่ละเอียดมาก แต่ฉันลองพวกเขาทั้งหมดโดยไม่ประสบความสำเร็จ ฉันมีรูปแบบที่มีอินพุตบางส่วนไปยังคอนโทรลเลอร์และควรดูผลลัพธ์ของคอนโทรลเลอร์บน div อื่น เมื่อฉันป้อนอินพุตใด ๆ ความบังเอิญจะหายไปและฉันจะมีค่าคงที่ 0.00 ใน div view ในขณะที่แอพทำงานอยู่
zahra

33

แทนที่จะใช้thisเป็นคำตอบที่ยอมรับแนะนำให้ใช้$parentแทน ดังนั้นในของpartial1.htmlคุณคุณจะมี:

<form ng-submit="$parent.addLine()">
    <input type="text" ng-model="$parent.lineText" size="30" placeholder="Type your message here">
</form>

หากคุณต้องการเรียนรู้เพิ่มเติมเกี่ยวกับขอบเขตในng-includeหรือคำสั่งอื่น ๆ ให้ตรวจสอบนี้: https://github.com/angular/angular.js/wiki/Understanding-Scopes#ng-include


1
สำหรับผู้อ่านเขาหมายถึง $scope.$parentแทนที่จะ$parentไม่ได้กำหนดตาม Angular
Sebastialonso

1
คำตอบนี้ช่วยประหยัดทั้งวันสำหรับฉัน! ขอบคุณมากที่ชี้ให้เห็นถึงการใช้ $ parent
Derek Webb

$ scope $ parent ผ่านการอ้างอิง? หรือเป็นเพียงสำเนาของพ่อแม่?
OMGPOP

1
@Sebastiallonso ผิด $ scope $ parent.lineText ไม่ได้กำหนดไว้ $ parent.lineText ใช้งานได้ this.lineText หรือเพียงแค่ lineText ก็ใช้งานได้
OMGPOP

มันใช้$scope.$parentงานได้สำหรับฉันในเชิงมุม 1.3.20
radtek

4

ฉันพบวิธีแก้ไขปัญหานี้โดยไม่ต้องผสมข้อมูลแม่และขอบเขตย่อย ตั้งค่าng-ifบนng-includeองค์ประกอบและตั้งเป็นตัวแปรขอบเขต ตัวอย่างเช่น :

<div ng-include="{{ template }}" ng-if="show"/>

trueในการควบคุมของคุณเมื่อคุณได้ตั้งค่าข้อมูลทั้งหมดที่คุณต้องการในขอบเขตย่อยของคุณแสดงแล้วชุด ng-includeจะคัดลอกในขณะนี้ชุดข้อมูลอยู่ในขอบเขตของคุณและตั้งอยู่ในขอบเขตย่อยของคุณ

กฎของหัวแม่มือคือการลดขอบเขตข้อมูลลึกขอบเขตที่อื่นคุณมีสถานการณ์นี้

แม็กซ์


ฉันใช้วิธีการนี้สำหรับปัญหาที่คล้ายกัน แต่ไม่เหมาะสำหรับทุกกรณี โดยเฉพาะอย่างยิ่งเมื่อคุณต้องการให้องค์ประกอบที่รวมจะไม่ถูกซ่อนอยู่ ...
iSpithash
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.