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

Ні, ви не повинні використовувати приватні змінні у своїх шаблонах.

Хоча мені подобається відповідь древмура і я бачу в ній досконалу концептуальну логіку, впроваджуючи це, це неправильно. Шаблони існують не в класах компонентів, а поза ними. Погляньте на це репо для підтвердження.

Єдина причина, чому це працює - це те, що privateключове слово TypeScript насправді не робить члена приватним. Компіляція щойно в часі відбувається в браузері під час виконання, а JS не має жодної концепції приватних членів (ще?). Кредит належить Сандеру Еліасу за те, що він поставив мене на правильний шлях.

За допомогою ngcта заздалегідь компіляції ви отримаєте помилки, якщо спробуєте отримати доступ до приватних членів компонента з шаблону. Клоніруйте демонстраційне репо, змініть MyComponentвидимість членів на приватну, і ви отримаєте помилки компіляції під час запуску ngc. Ось також відповідь, специфічна для складання заздалегідь часу.


6
це найкращий коментар і imo має бути прийнятою відповіддю. Справа не в тому, що ви можете використовувати приватні змінні, щойно переведені, що слід. Зберігайте код чистим!
Сем Влобергс

2
Це єдина правильна відповідь! Тепер Codelyzer попереджає вас, коли ви використовуєте приватний var у своєму шаблоні.
maxime1992

7
Моя єдина проблема з цим полягає в тому, як ви розмежовуєте фактично публічно оголених членів, таких як @ Inputs та Outputs членам, яких ми хочемо виставити лише нашому шаблону, а не на зовнішній світ. Якщо ви будуєте компоненти для багаторазового використання там, де ви хочете, щоб методи / члени були доступні шаблону, але не для інших компонентів. Я вважаю, що оригінальна відповідь правильна. Шаблони є частиною компонента.
Ешг

1
Я погоджуюся з @Ashg - і не тільки з Wrt Inputs and Outputs. Що робити, коли я хочу спілкуватися між компонентами, наприклад, вводячи батьківський компонент у свою дочірню. Після цього дочірній компонент може бачити все, що батько виставляє своєму шаблону, а не лише методи, які батько хоче викрити у зовнішньому світі. У межах обмежень Angular ця відповідь залишається правильною, але я не думаю, що ця конструкція була продумана.
Дан Кінг

Це хороша відповідь, оскільки він стосується обмежень у складанні AoT від Angular та способів їх обійти. Однак питання IMO було концептуальним (навмисно чи ні). Концептуально шаблони є частиною визначень класів. Шаблони не розширюють і не успадковують класи, і вони не отримують доступу до об'єктів з екземплярами зовнішньо ... це навпаки. Шаблони визначаються всередині самого класу, тому концептуально вони є частиною класу і концептуально повинні мати доступ до приватних членів.
A-Diddy

85

Редагувати: Ця відповідь зараз неправильна. Офіційних вказівок з цієї теми не було, коли я розміщував її, але як пояснено у відповіді @ Ярослова (відмінна і правильна), це вже не так: Codelizer тепер попереджає, а компіляція AoT не зможе посилатися на приватні змінні в шаблонах компонентів. . Однак на концептуальному рівні все тут залишається дійсним, тому я залишу цю відповідь, як здається, була корисною.


Так, це очікується.

Майте на увазі, що privateта інші модифікатори доступу - це конструкції Typescript, тоді як компонент / контролер / шаблон - це кутові конструкції, про які Typescript нічого не знає. Модифікатори доступу контролюють видимість між класами: Створення поля privateне дозволяє іншим класам мати доступ до нього, але шаблони та контролери - це речі, які існують у межах класів.

Це технічно не відповідає дійсності, але (замість того, щоб зрозуміти, як класи відносяться до декораторів та їх метаданих), можливо, було б корисно подумати про це так, адже важлива річ (IMHO) - перейти від роздумів про шаблон і контролер як про окремий суб'єкти, які думають про них як про уніфіковані частини конструкції Компонента - це один з головних аспектів ментальної моделі ng2.

Думаючи про це таким чином, очевидно, ми очікуємо, що privateзмінні класу компонентів будуть видимими в його шаблоні, з тієї ж причини ми очікуємо, що вони будуть видимими у privateметодах цього класу.


3
По-перше, я думав так само, як ти малювавморе. Але я оновив tslint до 4.02, а codelyzer - до 2.0.0-beta.1, і у мене виникли помилки, які сказали, що я не можу використовувати приватне під час доступу до змінних. Тож відповідь @ Ярослава видається більш підходящою.
maxime1992

8
Я погоджуюся, що модель компонента не має сенсу не бачити його приватних змінних, вони, мабуть, повинні бути перенесені в один клас під час компіляції, я маю на увазі, ви повинні піддавати особливості компонентів, ознаки та функції всі інші компоненти, щоб ви могли використовувати ті, що є у вашому шаблоні, не кажучи вже про зовнішні зміни або дзвінки до них, можуть спричинити потенційну несподівану поведінку на готовому компоненті
Феліпе,

1
@drewmoore, привіт, я кодую кутовий лише кілька місяців. Я зіткнувся з цим питанням. Чи є додаткові дискусії з цього приводу? Оскільки я не знаходжу нічого конкретного щодо того, за якою схемою слід наслідувати. imo, оскільки варто того, що є, це, здається, порушує розділення коду.
Едгар

2
@drewmoore, я мушу сказати, що я повністю згоден з вашою логікою anser. і я боюся, що команда Angular трохи заплуталася. в режимі AOT вони не дозволяють приватним членам, а в документах вони заявляють інакше, що у випадку з приватними членами абсолютно зміцнює вашу точку зору і лише додає більше хаосу цій темі. З Документів: "Кутовий трактує шаблон компонента як належний до компонента. Компонент та його шаблон довіряють один одному неявно. Тому власний шаблон компонента може прив'язуватися до будь-якого властивості цього компонента, з або без декоратора вводу * @ *. "
Орел Еракі

@drewmoore, Посилання на документи: angular.io/guide/attribute-directives#appendix-why-add-input (я знаю, що це головним чином фокус на декораторі вводу, але багато з чого вони говорять не лише пов'язані з це)
Орел Еракі

16

Незважаючи на те, що приклад коду вказує, що питання про TypeScript у нього немає тег. Angular2 також доступний для Dart, і це помітна різниця для Dart.

В Dart шаблон не може посилатися на окремі змінному клас компонента, тому що Dart на відміну від машинопису ефективно перешкоджає доступу приватних членів від зовнішньої сторони.

Я все ще повертаюся до пропозиції @drewmoores, щоб подумати про компонент і його шаблон, як про одне ціле.

Оновлення (TS) Здається, що в режимі офлайн-компіляції доступ до приватних ресурсів стане більш обмеженим у Angular2 TS, а також https://github.com/angular/angular/isissue/11422


2
Чи можливо мати компілятор Typescript для обмеження доступу приватних змінних до перегляду?
Меттью Харвуд

Не знаю. Я думаю, що не.
Гюнтер Зехбауер

2
Я б подумав, що, якщо вони є приватними, це може вплинути на тест того, наскільки правильно перевіряється компонент? Наприклад, якщо я створюю компонент у контексті тесту, я не зможу викликати ці приватні методи з мого тесту, щоб підтвердити, що взаємодія шаблон / клас працює. Я ще цього не пробував, тому вибачте, якщо це очевидно :)
Сем Сторі

У Dart ви не можете отримати доступ до приватних учасників тестів. Існує багато дискусій (незалежно від мови), чи слід це підтримувати та чи варто взагалі тестувати приватний API. Перевірка загальнодоступного API повинна мати можливість дістатися до кожного кодового шляху. Я думаю, що це взагалі розумно. У Dart приватна є бібліотека (яка може складатися з декількох файлів), що робить загальнодоступний API досить широким - IMHO занадто широким для одиничного тестування.
Günter Zöchbauer

3

Приватні змінні можна використовувати в шаблоні компонента. Дивіться посібник angular2 для посібника: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-child-setter

Більш детальне пояснення щодо державних / приватних членів класів у машинописному тексті можна знайти тут: 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, щоб отримати clientName ... так що виграшу немає
LeagueOfJava

Це неправильна практика підкреслення користувача для приватних змінних.
Флоріан Лейтгеб

1
@FlorianLeitgeb Чому саме це роблять офіційні документи Angular ? private _name = '';
ruffin

Тоді цей фрагмент коду не було переглянуто належним чином. Вони слідують конвенції стиль, який оголошений в стиль керівництва тут . А також у розділі класів Typescript на їхній сторінці тут не використовується підкреслення.
Флоріан Лейтгеб

1
@FlorianLeitgeb Що таке пропоноване рішення щодо перехоплення методів сеттера, як показано у посиланні, розміщеному ruffin? тобто як ви називаєте приватне поле резервного копіювання вашого сетера?
El Ronnoco

1

Коротка відповідь - ні, ви не повинні мати доступ до приватних членів із шаблону, оскільки він технічно відокремлений від файлу TS.


0

У tsconfig.app.json, якщо ви надаєте опцію 'fullTemplateTypeCheck' у параметрах компілятора, ви можете побачити всі недійсні посилання у файлах html вашого проекту під час створення проекту.

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

}

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.