Angular2 - должны ли быть доступны частные переменные в шаблоне?

145

Если переменная объявлена 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
}
3gwebtrain
источник

Ответы:

230

Нет, вам не следует использовать частные переменные в своих шаблонах.

Хотя мне нравится ответ Дрюмура и я вижу в нем идеальную концептуальную логику, с точки зрения реализации это неверно. Шаблоны существуют не внутри классов компонентов, а вне их. Взгляните на это репо для доказательства.

Единственная причина, по которой это работает, заключается в том, что privateключевое слово TypeScript на самом деле не делает член закрытым. Компиляция Just-in-Time происходит в браузере во время выполнения, а в JS нет концепции частных членов (пока?). Благодарим Сандера Элиаса за то, что он направил меня на правильный путь.

С ngcкомпиляцией и с опережающей компиляцией вы получите ошибки, если попытаетесь получить доступ к закрытым членам компонента из шаблона. Клонируйте демонстрационное репо, измените MyComponentвидимость участников на частную, и при запуске вы получите ошибки компиляции ngc. Вот также ответ, специфичный для компиляции Ahead-of-Time.

Ярослав Админ
источник
6
это лучший комментарий, и я должен быть принятым ответом. Дело не в том, что вы можете использовать частные переменные после переноса, вам нужно ... Держите код в чистоте!
Sam Vloeberghs
2
Это единственный верный ответ! Codelyzer теперь предупреждает вас, когда вы используете частную переменную в своем шаблоне.
maxime1992
8
Моя единственная проблема с этим заключается в том, как различать фактические публично открытые члены, такие как @Inputs и Outputs, для членов, которые мы хотим предоставлять только нашему шаблону, а не внешнему миру. Если вы создаете повторно используемые компоненты, где вы хотите, чтобы методы / члены были доступны для шаблона, но не для других компонентов. Я думаю, что первоначальный ответ правильный. Шаблоны являются частью компонента.
Ашг 04
1
Я согласен с @Ashg - и не только с входами и выходами. А что насчет того, когда я хочу общаться между компонентами, например, вставляя родительский компонент в его дочерний. Затем дочерний компонент может видеть все, что родитель предоставляет своему шаблону, а не только методы, которые родитель хочет предоставить внешнему миру. В рамках ограничений Angular этот ответ остается правильным, но я не думаю, что этот дизайн был хорошо продуман.
Дэн Кинг
Это хороший ответ, поскольку он устраняет ограничения в компиляции Angular AoT и способы их обойти. Однако в IMO вопрос был концептуальным (намеренно или нет). Концептуально шаблоны являются частью определений классов. Шаблоны не расширяют и не наследуют классы, и они не обращаются к созданным объектам извне ... все наоборот. Шаблоны определяются внутри самого класса, поэтому концептуально они являются частью класса и концептуально должны иметь доступ к закрытым членам.
A-Diddy,
86

Изменить: этот ответ теперь неверен. Когда я опубликовал его, не было официального руководства по теме, но, как объясняется в ответе @ Yaroslov (отличный и правильный), это уже не так: Codelizer теперь предупреждает, а компиляция AoT не будет работать при ссылках на частные переменные в шаблонах компонентов . Тем не менее, на концептуальном уровне все здесь остается в силе, поэтому я оставлю этот ответ, поскольку он, кажется, был полезным.


Да, это ожидаемо.

Имейте в виду, что privateи другие модификаторы доступа являются конструкциями Typescript, тогда как Component / controller / template - это конструкции angular, о которых Typescript ничего не знает. Модификаторы доступа управляют видимостью между классами: создание поля privateпредотвращает доступ к нему других классов , но шаблоны и контроллеры - это вещи, которые существуют внутри классов.

Технически это не так, но (вместо понимания того, как классы связаны с декораторами и их метаданными), может быть полезно думать об этом таким образом, потому что важно (ИМХО) отказаться от мышления о шаблоне и контроллере как о отдельных сущностей, чтобы думать о них как о единых частях конструкции Компонент - это один из основных аспектов ментальной модели ng2.

Рассуждая таким образом, мы, очевидно, ожидаем, что privateпеременные класса компонента будут видны в его шаблоне, по той же причине, по которой мы ожидаем, что они будут видны в privateметодах этого класса.

Дрю Мур
источник
3
Сначала я подумал так же, как ты, Дрюмур. Но я обновил tslint до 4.02 и codelyzer до 2.0.0-beta.1, и у меня были ошибки, в которых говорилось, что я не могу использовать private при доступе к переменным в представлении. Так что ответ @Yaroslav кажется более подходящим.
maxime1992
8
Я согласен с тем, что для компонентной модели не имеет смысла не видеть свои частные переменные, они, вероятно, должны быть объединены в один и тот же класс во время компиляции, я имею в виду, что вы должны предоставить специфические для компонента черты, объекты и функции для все остальные компоненты, чтобы вы могли использовать их в своем шаблоне, не говоря уже о внешних настройках или вызовах, которые могут вызвать потенциально неожиданное поведение готового компонента
Felype
1
@drewmoore, привет, я кодирую angular всего несколько месяцев. Я столкнулся с этой проблемой. Есть ли по этому поводу дальнейшие дебаты? Поскольку я не нахожу ничего конкретного, по какому образцу следовать. имо, так как оно того стоит, похоже, нарушает разделение кода.
Эдгар
2
@drewmoore, я должен сказать, что полностью согласен с вашей логикой anser. и я боюсь, что команда Angular немного напортачила. в режиме AOT они не допускают частных участников, в то время как в документах они утверждают иное, что в случае частных участников полностью укрепляет вашу точку зрения и только добавляет хаоса в эту тему. Из Документов: «Angular рассматривает шаблон компонента как принадлежащий компоненту. Компонент и его шаблон неявно доверяют друг другу. Следовательно, собственный шаблон компонента может быть привязан к любому свойству этого компонента, с декоратором * @ * Input или без него. "
Орел Эраки
@drewmoore, Ссылка на документы: angular.io/guide/attribute-directives#appendix-why-add-input (я знаю, что он в основном сосредоточен на декораторе ввода, но многое из того, о чем они говорят, связано не только с it)
Орел Эраки
16

Несмотря на то, что пример кода указывает на то, что вопрос касается TypeScript, у него нет тег. Angular2 также доступен для Dart, и это заметное отличие от Dart.

В дротике шаблон не может ссылаться на отдельные переменном класс компонента, потому что Dart в отличии от машинописи эффективно препятствует доступу частных членов от внешней стороны.

Я все еще поддерживаю предложение @drewmoores подумать о компоненте и его шаблоне как о едином блоке.

Обновление (TS) Похоже, что с автономной компиляцией доступ к частным свойствам станет более ограниченным в Angular2 TS, а также https://github.com/angular/angular/issues/11422

Гюнтер Цёхбауэр
источник
2
Возможно ли, чтобы компилятор Typescript ограничил доступ к частным переменным для представления?
Мэтью Харвуд
Я не знаю. Думаю, нет.
Günter Zöchbauer
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 ) и нигде не вижу, чтобы предполагалось, что использование частных переменных в шаблонах нормально. Напротив, они используют геттеры и сеттеры для доступа к приватным переменным из шаблона.
Себастьян Шартье,
3

Обходной путь может заключаться в использовании частных переменных в файле ts и использовании геттеров.

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

Это хороший подход, поскольку ts-файл и html остаются независимыми. Даже если вы измените имя переменной _userName в файле ts, вам не нужно вносить никаких изменений в файл шаблона.

Франклин Благочестивый
источник
Я думаю, что если вы измените _userName на _clientName, например, для согласованности, вам нужно будет изменить геттер, чтобы получить clientName ... так что выигрыша нет
LeagueOfJava 09
Использование подчеркивания для частных переменных - плохая практика.
Флориан Лейтгеб
1
@FlorianLeitgeb Почему официальные документы Angular это делают ? private _name = '';
ruffin
Тогда этот фрагмент кода не был рассмотрен должным образом. Они следуют стилевому соглашению, которое заявлено в руководстве по стилю здесь . А также в разделе классов Typescript на их странице здесь не используется подчеркивание.
Флориан Лейтгеб
1
@FlorianLeitgeb Итак, каким было бы предложенное решение для перехвата методов установки, как показано в ссылке, опубликованной ruffin? т.е. что вы называете личным резервным полем установщика?
El Ronnoco
1

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

Ivens Applyrs
источник
0

В tsconfig.app.json, если вы укажете опцию fullTemplateTypeCheck в параметрах компилятора, вы сможете увидеть все недопустимые ссылки в html-файлах вашего проекта во время сборки проекта.

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

}

Хушбу Сурьяванши
источник