AngularJS: динамическая пользовательская директива с несколькими шаблонами

Я Java-разработчик, работающий над сайд-проектом. Я решил использовать AngularJS, чтобы использовать мой RESTful веб-сервис.

Моя структура JSON выглядит следующим образом:

[
  {
    "generatorName": "name1",
    "constructorParams": [
      {
        "type": "Boolean",
        "value": "true",
      },
      {
        "type": "Integer",
        "value": "2",
      }
    ]
  },
  {
    "generatorName": "name2",
    "constructorParams": [
      {
        "type": "Integer",
        "value": "10",
      },
      {
        "type": "Integer",
        "value": "10",
      }
    ]
  }
]

Моя цель - отобразить конкретное (например, число, текст и т. Д.) Поле ввода на основе "типа" параметра конструктора и инициализировать его "значением". Итак, если был выбран первый генератор, я бы хотел что-то вроде этого:

<html>
    <select>
        <option selected="selected" value="true">Yes</option>
        <option value="false">No</option>
    </select>

    <input type="number" value="2">
<html>

Я прочитал некоторые темы и решил использовать пользовательскую директиву внутри моего цикла:

<p ng-repeat="param in selectedGenerator.constructorParams">
      <constructor-param param="{{param}}"></constructor-param>
</p>

Вот моя пользовательская директива:

app.directive("constructorParam", function() {
    return {
        scope : {
            param : '@'
        },
        templateUrl : '/html_templates/constructor_param_template.html'
    };
});

И вот шаблон:

<div ng-switch="{{param.type}}">
    <div ng-switch-when="Integer">
        <input type="number" ng-attr-name="{{param.type}}" min="0" ng-attr-value="{{param.value}}">
    </div>

    <div ng-switch-when="Boolean">
        <select ng-if="{{param.value}}" ng-attr-name="{{param.type}}">
            <option selected="selected" value="true">Yes</option>
            <option value="false">No</option>
        </select>

        <select ng-if="!{{param.value}}" ng-attr-name="{{param.type}}">
            <option value="true">Yes</option>
            <option selected="selected" value="false">No</option>
        </select>
    </div>

    <div ng-switch-when="String">
        <input type="text" ng-attr-name="{{param.type}}" ng-attr-value="{{param.value}}">
    </div>

    <div ng-switch-when="Double">
        <input type="number" ng-attr-name="{{param.type}}" step="0.01" min="0" ng-attr-value="{{param.value}}">
    </div>
</div>

Это не работает. Я вижу в инструментах разработчика Chrome, что директива запущена, но она не дает видимых результатов. Мои вопросы:

1) Правильно ли я передал объект param в пользовательский элемент директивы?

2) я не уверен насчет scope директивы - я также пытался param : '=param' - это тоже не работает...

3) Как мне прочитать свойства переданного объекта в шаблоне? Я пробовал: value="{{param.type}}", value={{param.type}} а также ng-attr-value="{{param.value}}", Ничто не работает, но это может быть совершенно другая причина...

4) Могу ли я использовать префикс "ng-attr-" для всех атрибутов HTML такого элемента, как имя и значение?

5) Код моего шаблона - это именно то, что я вставил - нужно ли мне сделать его правильной HTML-структурой с головой, телом и т. Д.? Должен ли я прикрепить <script> с AngularJS? Я сделал это, но еще раз, без изменений.

6) Сценарий использования для всей истории состоит в том, чтобы выбрать конкретный генератор из раскрывающегося списка и отобразить его параметры конструктора указанным способом. Таким образом, он должен восстановить HTML с заменой генератора. Я предполагаю, что это сделано в цикле ng-repeat, но, пожалуйста, подтвердите это.

Большое спасибо за ваш вклад!:)

3 ответа

Решение

Прежде всего, спасибо вам обоим за помощь! К сожалению, я не могу пометить ни один из приведенных ответов как правильный, потому что мне приходится смешивать их, чтобы получить то, что я искал.

Я бы не стал здесь подробно останавливаться, позвольте мне поделиться с вами окончательным кодом:

<!-- container -->
<p ng-repeat="param in selectedGenerator.constructorParams">
  <constructor-param param="param"></constructor-param>
</p>

<!-- template -->
<div ng-switch="param.type">
    <div ng-switch-when="Integer">
        <input type="number" name={{param.type}} min="0" value={{param.value}}>
    </div>

    <div ng-switch-when="Boolean">
        <select ng-if="param.value" name={{param.type}}>
            <option selected="selected" value="true">Yes</option>
            <option value="false">No</option>
        </select>

        <select ng-if="!param.value" name={{param.type}}>
            <option value="true">Yes</option>
            <option selected="selected" value="false">No</option>
        </select>
    </div>

    <div ng-switch-when="String">
        <input type="text" name={{param.type}} value={{param.value}}>
    </div>

    <div ng-switch-when="Double">
        <input type="number" name={{param.type}} step="0.01" min="0" value={{param.value}}>
    </div>
</div>

И вот директива, вы оба правильно поняли:

app.directive("constructorParam", function() {
  return {
    scope: {
      param: '='
    },
    templateUrl: '/html_templates/constructor_param_template.html'
  };
});

Еще раз - большое спасибо, я бы не решил эту проблему так быстро без вашей помощи!

Когда вы делаете param : '@' это "привязка текста". Это полезно в том случае, если вы хотите указать Angular не интерпретировать то, что вы привязываете к своему атрибуту, как свойство в области, а как непосредственно строку.

Так что если вы сделаете

<my-custom-directive param="hello"></my-custom-directive>

Тогда в вашей директиве, param будет равна строке "hello", Хотя, если вы связываете с param используя двустороннюю привязку param : '=' то Angular будет искать hello свойство в области видимости вместо того, чтобы принимать его как строковый литерал.

В вашем случае, когда вы делаете param="{{param}}" Angular сначала распаковывает "param", просматривая область видимости, в строковый литерал, затем создает привязку. Так что, хотя это могло бы сработать, если param была строка, в вашем случае это объект, поэтому я не думаю, что он будет играть хорошо. Так что я бы просто сделал прямую привязку к нему (см. Мой окончательный код ниже).

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

app.directive("constructorParam", function() {
  return {
    scope: {
      param: '='
    },
    templateUrl: '/html_templates/constructor_param_template.html'
  };
});
<!-- container -->
<p ng-repeat="param in selectedGenerator.constructorParams">
  <constructor-param param="{{param}}"></constructor-param>
</p>

<!-- TEMPLATE -->

<div ng-switch="param.type">
  <div ng-switch-when="Integer">
    <input type="number" ng-attr-name="param.type" min="0" ng-attr-value="param.value">
  </div>

  <div ng-switch-when="Boolean">
    <select ng-if="param.value" ng-attr-name="param.type">
            <option selected="selected" value="true">Yes</option>
            <option value="false">No</option>
        </select>

    <select ng-if="!param.value" ng-attr-name="param.type">
            <option value="true">Yes</option>
            <option selected="selected" value="false">No</option>
        </select>
  </div>

  <div ng-switch-when="String">
    <input type="text" ng-attr-name="param.type" ng-attr-value="param.value">
  </div>

  <div ng-switch-when="Double">
    <input type="number" ng-attr-name="param.type" step="0.01" min="0" ng-attr-value="param.value">
  </div>
</div>

Если это все еще не работает, дайте мне знать, чтобы я мог попробовать это в CodePen.

1) Нет, вам нужно убрать фигурные скобки при передаче значений в директиву

<constructor-param param="param"></constructor-param>

2,3) в директивном использовании = вместо @, Так как @ принять строковое значение параметра и = принять значение параметра

scope: {
    param: '='
},

4) если вам нужно связать данные, используйте ng-model вместо ng-attr

5) Вам не нужно добавлять html или тег body внутри constructor_param_template.html шаблон.

6) это делает нг-повтор. как только массив обновится, он будет динамически обновлять DOM

демонстрация

Другие вопросы по тегам