Angular2 - ตัวแปรส่วนตัวควรสามารถเข้าถึงได้ในแม่แบบหรือไม่


143

หากมีการประกาศตัวแปรprivateในคลาสคอมโพเนนต์ฉันจะสามารถเข้าถึงตัวแปรนั้นในเทมเพลตขององค์ประกอบนั้นได้หรือไม่

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>{{title}}</h2>
      <h2>Hello {{userName}}</h2> // I am getting this name
    </div>
  `,
})
export class App {
  public title = 'Angular 2';
  private userName = "Test Name"; //declared as private
}

คำตอบ:


226

ไม่คุณไม่ควรใช้ตัวแปรส่วนตัวในแม่แบบของคุณ

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

เหตุผลเดียวที่ทำให้มันเป็นเพราะprivateคำหลักของ TypeScript ไม่ได้ทำให้สมาชิกเป็นส่วนตัว การรวบรวมแบบทันเวลาเกิดขึ้นในเบราว์เซอร์ที่รันไทม์และ JS ไม่มีแนวคิดของสมาชิกส่วนตัว (ยัง?) เครดิตไปที่Sander Eliasเพื่อให้ฉันไปถูกทาง

ด้วยการngcรวบรวมและนำหน้าเวลาคุณจะได้รับข้อผิดพลาดถ้าคุณพยายามเข้าถึงสมาชิกส่วนตัวของส่วนประกอบจากเทมเพลต repo สาธิตโคลนเปลี่ยนแปลงการมองเห็นของสมาชิกข้อผิดพลาดของสะสมส่วนตัวและคุณจะได้รับเมื่อทำงานMyComponent ngcต่อไปนี้เป็นคำตอบเฉพาะสำหรับการรวบรวมล่วงหน้า


6
นี่เป็นความคิดเห็นที่ดีที่สุดและ IMO ควรเป็นคำตอบที่ยอมรับได้ ไม่ใช่ว่าคุณสามารถใช้ตัวแปรส่วนตัวเมื่อ transpiled แล้วคุณควร .. รักษารหัสให้สะอาด!
Sam Vloeberghs

2
นี่เป็นคำตอบเดียวเท่านั้นที่ถูกต้อง! ขณะนี้ Codelyzer เตือนคุณเมื่อคุณใช้ var ส่วนตัวในเทมเพลตของคุณ
maxime1992

7
ปัญหาเดียวของฉันคือสิ่งนี้คุณจะแยกความแตกต่างระหว่างสมาชิกที่เปิดเผยจริงเช่น @Inputs และ Outputs ให้กับสมาชิกที่เราต้องการเปิดเผยเฉพาะกับแม่แบบของเราไม่ใช่โลกภายนอก หากคุณกำลังสร้างส่วนประกอบที่นำกลับมาใช้ใหม่ได้ซึ่งคุณต้องการให้สมาชิกสามารถเข้าถึงวิธีการ / สมาชิก แต่ไม่สามารถใช้กับส่วนประกอบอื่น ๆ ได้ ฉันคิดว่าคำตอบดั้งเดิมนั้นถูกต้อง เทมเพลตเป็นส่วนหนึ่งของส่วนประกอบ
Ashg

1
ฉันเห็นด้วยกับ @Ashg - และไม่เพียง แต่เขียนอินพุตและเอาต์พุตเท่านั้น จะทำอย่างไรเมื่อฉันต้องการสื่อสารระหว่างส่วนประกอบเช่นโดยการฉีดองค์ประกอบหลักลงในลูก จากนั้นองค์ประกอบลูกสามารถเห็นทุกสิ่งที่ผู้ปกครองเปิดเผยให้กับเทมเพลตแทนที่จะเป็นเพียงวิธีการที่ผู้ปกครองต้องการเปิดเผยสู่โลกภายนอก ภายในข้อ จำกัด ของ Angular คำตอบนี้ยังคงเป็นคำตอบที่ถูกต้อง แต่ฉันไม่คิดว่าการออกแบบนี้ได้รับการคิดมาอย่างดี
Dan King

นี่เป็นคำตอบที่ดีเนื่องจากข้อ จำกัด ภายในการรวบรวม AoT ของ Angular และวิธีการแก้ไข อย่างไรก็ตาม IMO คำถามเป็นแนวคิด (โดยเจตนาหรือไม่) แนวคิดแม่แบบเป็นส่วนหนึ่งของคำจำกัดความของคลาส เทมเพลตจะไม่ขยายหรือสืบทอดคลาสและพวกเขาไม่สามารถเข้าถึงออบเจ็กต์ภายนอกได้ ... เป็นอีกวิธีหนึ่ง เทมเพลตนั้นถูกกำหนดไว้ในชั้นเรียนดังนั้นในความคิดพวกเขาเป็นส่วนหนึ่งของคลาสและแนวคิดควรมีสิทธิ์เข้าถึงสมาชิกส่วนตัว
A-Diddy

85

แก้ไข: คำตอบนี้ไม่ถูกต้องในขณะนี้ ไม่มีคำแนะนำอย่างเป็นทางการในหัวข้อเมื่อฉันโพสต์ แต่ตามที่อธิบายไว้ใน @ Yaroslov's (ยอดเยี่ยมและถูกต้อง) คำตอบนี่ไม่ใช่กรณี: Codelizer ตอนนี้เตือนและรวบรวม AoT จะล้มเหลวในการอ้างอิงตัวแปรส่วนตัวในแม่แบบองค์ประกอบ . ที่กล่าวว่าในระดับแนวคิดทุกอย่างที่นี่ยังคงใช้ได้ดังนั้นฉันจะทิ้งคำตอบนี้ไว้เพราะดูเหมือนว่าจะเป็นประโยชน์


ใช่คาดว่าจะเป็นเช่นนี้

โปรดทราบว่าprivateและตัวดัดแปลงการเข้าถึงอื่น ๆ คือโครงสร้างแบบ typescript ในขณะที่ส่วนประกอบ / ตัวควบคุม / แม่แบบเป็นโครงสร้างเชิงมุมที่ typescript ไม่ทราบอะไรเลย ตัวดัดแปลงการเข้าถึงควบคุมการเปิดเผยระหว่างคลาส: การสร้างเขตข้อมูลprivateป้องกันคลาสอื่นไม่ให้เข้าถึง แต่แม่แบบและตัวควบคุมเป็นสิ่งที่มีอยู่ภายในคลาส

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

เมื่อคิดอย่างนั้นเราก็คาดหวังว่าprivateตัวแปรในคลาสคอมโพเนนต์จะปรากฏในเทมเพลตด้วยเหตุผลเดียวกับที่เราคาดว่าจะสามารถมองเห็นได้ในprivateวิธีการในคลาสนั้น


3
ก่อนอื่นฉันคิดเหมือนคุณหล่อเลี้ยง แต่ฉันอัพเกรด tslint เป็น 4.02 และ codelyzer เป็น 2.0.0-beta.1 และฉันพบข้อผิดพลาดว่าฉันไม่สามารถใช้ส่วนตัวเมื่อเข้าถึงตัวแปรในมุมมอง คำตอบของ So @ Yaroslav ดูเหมือนจะเหมาะสมกว่า
maxime1992

8
ฉันยอมรับว่ามันไม่สมเหตุสมผลสำหรับโมเดลส่วนประกอบที่จะไม่สามารถเห็นตัวแปรส่วนตัวของมันพวกเขาน่าจะถูกบดเป็นคลาสเดียวกันในระหว่างการคอมไพล์ฉันหมายความว่าคุณต้องแสดงลักษณะเฉพาะของส่วนประกอบวัตถุและฟังก์ชั่นเพื่อ ส่วนประกอบอื่น ๆ ทั้งหมดเพื่อให้คุณสามารถใช้สิ่งเหล่านั้นในแม่แบบของคุณไม่ต้องพูดถึง tweaks ภายนอกหรือการเรียกไปยังสิ่งเหล่านั้นอาจทำให้เกิดพฤติกรรมที่ไม่คาดคิดในองค์ประกอบที่เสร็จสมบูรณ์
Felype

1
@rewmoore สวัสดีฉันได้รับการเข้ารหัสเชิงมุมเพียงบางเดือน ฉันกำลังเผชิญหน้ากับปัญหานี้ มีข้อโต้แย้งเพิ่มเติมเกี่ยวกับเรื่องนี้หรือไม่? ในขณะที่ฉันไม่พบสิ่งใดเป็นพิเศษเกี่ยวกับรูปแบบที่ต้องติดตาม imo เนื่องจากเป็นสิ่งที่คุ้มค่าดูเหมือนว่าจะเป็นการละเมิดการแยกรหัส
เอ็ดการ์

2
@drewmoore ฉันต้องบอกว่าฉันเห็นด้วยกับตรรกะของคุณทั้งหมด และฉันก็กลัวว่าทีมงานแองกูลาร์จะเลอะเทอะไปบ้าง ในโหมด AOT พวกเขาไม่อนุญาตให้สมาชิกส่วนตัวในขณะที่เอกสารที่พวกเขาอ้างว่าเป็นอย่างอื่นซึ่งในกรณีที่สมาชิกส่วนตัวเพิ่มจุดแข็งของคุณและเพิ่มความสับสนวุ่นวายมากขึ้นในหัวข้อนี้ จาก Docs: "Angular ปฏิบัติต่อเทมเพลตของส่วนประกอบว่าเป็นของคอมโพเนนต์คอมโพเนนต์และเทมเพลตของมันจะไว้วางใจซึ่งกันและกันโดยปริยายดังนั้นแม่แบบของคอมโพเนนต์นั้นอาจผูกกับคุณสมบัติใด ๆ ของส่วนประกอบนั้นโดยมีหรือไม่มี * decor * Input "
Orel Eraki

@drewmoore, ลิงก์สำหรับเอกสาร: angular.io/guide/attribute-directives#appendix-why-add-input@appendix- (ฉันรู้ว่ามันเน้นไปที่มัณฑนากรอินพุตเป็นส่วนใหญ่ แต่สิ่งที่พวกเขากำลังพูดถึงไม่เกี่ยวข้องกับ มัน)
Orel Eraki

16

แม้ว่าตัวอย่างรหัสระบุว่าคำถามเกี่ยวกับ TypeScript แต่ก็ไม่มี แท็ก Angular2 ยังมีให้สำหรับ Dart และนี่คือความแตกต่างที่น่าทึ่งของ Dart

ในโผแม่แบบไม่สามารถอ้างอิงตัวแปรส่วนตัวของชนชั้นองค์ประกอบเพราะโผในทางตรงกันข้ามกับ typescript ได้อย่างมีประสิทธิภาพป้องกันการเข้าถึงของสมาชิกในภาคเอกชนจากภายนอก

ฉันยังคงสนับสนุน @drewmoores ข้อเสนอแนะที่จะคิดเกี่ยวกับองค์ประกอบและมันเป็นแม่แบบเป็นหนึ่งหน่วยแม้ว่า

อัปเดต (TS) ดูเหมือนว่าการเข้าถึงการรวบรวมแบบออฟไลน์กับคุณสมบัติส่วนตัวจะมีข้อ จำกัด มากขึ้นใน Angular2 TS เช่นกันhttps://github.com/angular/angular/angular/angular/issues/11422


2
เป็นไปได้ไหมที่จะมีตัวรวบรวม typescript เพื่อ จำกัด ตัวแปรส่วนตัวที่สามารถเข้าถึงได้ในมุมมอง?
Matthew Harwood

ฉันไม่รู้ ฉันเดาว่าไม่.
GünterZöchbauer

2
ฉันคิดว่าการให้พวกเขาเป็นส่วนตัวอาจส่งผลกระทบต่อการทดสอบองค์ประกอบที่ถูกต้อง ตัวอย่างเช่นถ้าฉันสร้างองค์ประกอบในบริบทของการทดสอบฉันจะไม่สามารถเรียกวิธีการส่วนตัวเหล่านั้นจากการทดสอบของฉันเพื่อยืนยันว่าการโต้ตอบของแม่แบบ / คลาสใช้งานได้ ฉันไม่ได้พยายามนี้ยังดังนั้นยกโทษให้ฉันถ้าเรื่องนี้เป็นที่ชัดเจน :)
แซม Storie

ใน Dart คุณไม่สามารถเข้าถึงสมาชิกส่วนตัวในการทดสอบ มีการอภิปรายจำนวนมาก (ไม่ขึ้นอยู่กับภาษา) ว่าควรได้รับการสนับสนุนหรือไม่และควรทดสอบ API ส่วนตัวหรือไม่ การทดสอบ API สาธารณะควรจะสามารถเข้าถึงแต่ละเส้นทางของรหัสได้ ฉันคิดว่ามันสมเหตุสมผลโดยทั่วไป ใน Dart private ต่อห้องสมุด (ซึ่งอาจประกอบด้วยหลายไฟล์) ซึ่งทำให้ API สาธารณะค่อนข้างกว้าง - IMHO กว้างเกินไปสำหรับการทดสอบหน่วย
GünterZöchbauer

3

ตัวแปรส่วนตัวสามารถใช้ภายในเทมเพลตของส่วนประกอบ ดูคำแนะนำในการโกง angular2: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-child-setter

คำอธิบายรายละเอียดเพิ่มเติมเกี่ยวกับสมาชิกรัฐ / ภาคเอกชนของการเรียนใน typescript สามารถพบได้ที่นี่: https://www.typescriptlang.org/docs/handbook/classes.html

สมาชิกทั้งหมดโดยค่าเริ่มต้นเป็นสาธารณะ สมาชิกสาธารณะสามารถเข้าถึงได้จากนอกชั้นองค์ประกอบพร้อมกับคลาสอินสแตนซ์ แต่สมาชิกส่วนตัวสามารถเข้าถึงได้เฉพาะภายในฟังก์ชั่นสมาชิกระดับ


ฉันดูที่ลิงค์แรก ( angular.io/guide/component-interaction#!#parent-to-child-setter ) และฉันไม่เห็นว่าจะแนะนำให้ใช้ตัวแปรส่วนตัวในแม่แบบใด ในทางกลับกันพวกเขาใช้ getters และ setters เพื่อเข้าถึงตัวแปรส่วนตัวจากเทมเพลต
เซบาสเตียนชาร์เทียร์

3

วิธีแก้ปัญหาอาจใช้ตัวแปรส่วนตัวในไฟล์ ts และใช้ getters

private _userName = "Test Name";
get userName() {
  return this._userName;
}

นี่เป็นวิธีการที่ดีเพราะไฟล์ ts และ html ยังคงเป็นอิสระ แม้ว่าคุณจะเปลี่ยนชื่อตัวแปร _userName ในไฟล์ ts คุณไม่จำเป็นต้องทำการเปลี่ยนแปลงใด ๆ ในไฟล์เทมเพลต


ฉันคิดว่าถ้าคุณเปลี่ยน _userName เป็น _clientName เช่นเพื่อความมั่นคงคุณต้องเปลี่ยน getter เพื่อรับชื่อลูกค้า ... ดังนั้นจึงไม่มีการชนะ
LeagueOfJava

มันเป็นวิธีปฏิบัติที่ไม่ดีสำหรับผู้ใช้ขีดเส้นใต้สำหรับตัวแปรส่วนตัว
Florian Leitgeb

1
@FlorianLeitgeb ซึ่งเป็นเหตุผลที่เอกสารอย่างเป็นทางการเชิงมุมทำมัน ? private _name = '';
ruffin

จากนั้นข้อมูลโค้ดนี้ไม่ได้รับการตรวจสอบอย่างถูกต้อง พวกเขาปฏิบัติตามรูปแบบการประชุมซึ่งจะมีการประกาศในคู่มือรูปแบบที่นี่ และในส่วนคลาสของ typescript บนหน้าของพวกเขาที่นี่ไม่ได้ใช้ขีดล่าง
Florian Leitgeb

1
@ FlorianLeitgeb แล้วอะไรจะเป็นทางออกที่นำเสนอต่อการสกัดกั้นของ setter method ดังที่แสดงในลิงค์ที่โพสต์โดย ruffin? เช่นอะไรที่คุณเรียกว่าเขตข้อมูลสำรองส่วนตัวของผู้ตั้งค่าของคุณ?
El Ronnoco

1

คำตอบสั้น ๆ คือไม่คุณไม่ควรเข้าถึงสมาชิกส่วนตัวจากเทมเพลตเพราะจะแยกทางเทคนิคจากไฟล์ TS


0

ใน tsconfig.app.json หากคุณระบุตัวเลือก 'fullTemplateTypeCheck' ในตัวเลือกคอมไพเลอร์คุณสามารถดูการอ้างอิงที่ไม่ถูกต้องทั้งหมดในไฟล์ html ของโครงการของคุณในเวลาที่สร้างโครงการ

"angularCompilerOptions": {
"enableIvy": true,
"fullTemplateTypeCheck": true

}

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