0

AngularJS でフォ​​ーム ビルダーを作成しようとしています。フォーム構造全体は、次のように JSON オブジェクトで定義されます。

form = {
  "title": "Some form title",          // Title of the field
  "fieldsets": [                       // Each form is composed of several fieldsets 
    {
      "title": "First fieldset",       // Title of the fieldset
      "fields": [                      // Each fieldset is composed of several fields
        {
          "title": "First field",      // Title of the field, displayed in a label
          "type": "text"               // Type of the field which determines which partial to load
        },
        {
          "title": "Second field",
          "type": "date"
        },
      ]
    },
    {
      "title": "Second fieldset",
      "fields": [
        {
          "title": "First field",
          "type": "text"
        },
        {
          "title": "Second field",
          "type": "date"
        },
      ]
    }     
   ]
}

上記のような JSON オブジェクトを取得し、次のようなページ (jade テンプレート) にレンダリングします。

h5 {{ form.title }}
div(ng-repeat="fs in form.fieldsets")
  fieldset
    legend {{ fs.title }}
    div(ng-repeat="field in fs.fields")
      myfield(field="field")

myfield各フィールドを解析し、タイプに基づいて異なるパーシャルをレンダリングするカスタム ディレクティブです。コードは次のとおりです。

var appFilters = angular.module('appComponents', []);
appFilters.directive('myfield', ['$compile', '$http', '$templateCache', function($compile, $http, $templateCache){
  var getTemplate = function(contentType) {
    return $http.get('partials/' + contentType + '_field', {cache: $templateCache});
    // I get the partials here, for example for a field of type text, I load text_field.jade
  };

  var linker = function(scope, element, attrs){

    scope.edit_field = function(field) {
      field.type = "template";
    };

    var loader = getTemplate(scope.field.type);

    var promise = loader.success(function(html) {
      element.html(html);
    }).then(function(response) {
      element.replaceWith($compile(element.html())(scope));
    });
  };

  return {
    restrict: 'E',
    scope: {
      field:'='
    },
    link: linker
  };
}]);

私はいくつかのパーシャルを持っています。これらはすべて、 という名前の 1 つの基本テンプレートから継承しfield.jadeます。ベース テンプレートと、それを継承する別のテンプレートを次に示します。

field.jade: (他のパーシャルのベース テンプレート):

div
  block _title

div
  div
    block _label
      label {{ field.title }}:
  div
    block _field
  div
    block _controls
      a.control(ng-click="edit_field(field)") Edit

text_field.jade: (テキスト型のフィールドの一部)

extend field

block _field
  input(type="text")

template_field.jade: (編集モードの場合のフィールドの一部)

extend field

block _label
  input(type="text", ng-model="field.title")
  // The user can edit the field label here

block _field
  select
  // Here the user can select from several different field types

ユーザーがEditボタンをクリックすると、field.typeが変更されtemplate、AngularJS がtemplate_field.jadeメイン ビューの代わりにビューをロードするようになりました (のようにtext_field.jade)。

代わりにAngularJSにtemplated_field.jadeパーシャルをリロードするように指示する方法を知っている人はいますか?

PS: このためのフィドルを作成したかったのですが、複雑すぎて実行するためにいくつかの異なるファイルをインポートする必要があったため、フィドルの作成を断念しました。

4

1 に答える 1

1

私はそれを回避する方法を見つけました。それはうまくいきますが、それが最善の方法であるかどうかはわかりません。私の関数では、関数を手動でedit_field呼び出す必要があります。linker

scope.edit_field = function(field) {
  field.type = "template";
  linker(scope, element, attrs);
};

また、 への呼び出しを に置き換える必要がreplaceWith()ありましhtml()た。理由はわかりませんがreplaceWith()、最初に呼び出されたときにしか機能しません。
したがって、この行:

element.replaceWith($compile(element.html())(scope));

これに置き換える必要があります:

element.html($compile(element.html())(scope));

最終的なコードは次のとおりです。

var appFilters = angular.module('appComponents', []);
appFilters.directive('myfield', ['$compile', '$http', '$templateCache', function($compile, $http, $templateCache){
  var getTemplate = function(contentType) {
    return $http.get('partials/' + contentType + '_field', {cache: $templateCache});
    // I get the partials here, for example for a field of type text, I load text_field.jade
  };

  var linker = function(scope, element, attrs){

    scope.edit_field = function(field) {
      field.type = "template";
      linker(scope, element, attrs);
    };

    var loader = getTemplate(scope.field.type);

    var promise = loader.success(function(html) {
      element.html(html);
    }).then(function(response) {
      element.html($compile(element.html())(scope));
    });
  };

  return {
    restrict: 'E',
    scope: {
      field:'='
    },
    link: linker
  };
}]);

ここで間違いを犯している場合は、修正してください。

于 2013-11-04T23:03:34.760 に答える