developer tip

지시문 내에서 템플릿 사용자 지정

copycodes 2020. 8. 21. 07:57
반응형

지시문 내에서 템플릿 사용자 지정


다음과 같이 Bootstrap의 마크 업을 사용하는 양식이 있습니다.

<form class="form-horizontal">
  <fieldset>
    <legend>Legend text</legend>
    <div class="control-group">
      <label class="control-label" for="nameInput">Name</label>
      <div class="controls">
        <input type="text" class="input-xlarge" id="nameInput">
        <p class="help-block">Supporting help text</p>
      </div>
    </div>
  </fieldset>
</form>

다음과 같이 새로운 지시문 (form-input)으로 줄이고 싶은 많은 상용구 코드가 있습니다.

<form-input label="Name" form-id="nameInput"></form-input>

생성 :

   <div class="control-group">
      <label class="control-label" for="nameInput">Name</label>
      <div class="controls">
        <input type="text" class="input-xlarge" id="nameInput">
      </div>
    </div>

저는 간단한 템플릿을 통해이 정도 작업을합니다.

angular.module('formComponents', [])
    .directive('formInput', function() {
        return {
            restrict: 'E',
            scope: {
                label: 'bind',
                formId: 'bind'
            },
            template:   '<div class="control-group">' +
                            '<label class="control-label" for="{{formId}}">{{label}}</label>' +
                            '<div class="controls">' +
                                '<input type="text" class="input-xlarge" id="{{formId}}" name="{{formId}}">' +
                            '</div>' +
                        '</div>'

        }
    })

그러나 더 많은 고급 기능을 추가해야 할 때가 있습니다.

템플릿에서 기본값을 지원하려면 어떻게해야합니까?

내 지시문의 선택적 속성으로 "type"매개 변수를 노출하고 싶습니다. 예 :

<form-input label="Password" form-id="password" type="password"/></form-input>
<form-input label="Email address" form-id="emailAddress" type="email" /></form-input>

그러나 아무것도 지정하지 않으면 기본값으로 "text". 어떻게 지원할 수 있습니까?

속성 유무에 따라 템플릿을 사용자 정의하려면 어떻게해야합니까?

"필수"속성이있는 경우 지원할 수 있기를 바랍니다. 예 :

<form-input label="Email address" form-id="emailAddress" type="email" required/></form-input>

If required is present in the directive, I'd like to add it to the generated <input /> in the output, and ignore it otherwise. I'm not sure how to achieve this.

I suspect these requirements may have moved beyond a simple template, and have to start using the pre-compile phases, but I'm at a loss where to start.


angular.module('formComponents', [])
  .directive('formInput', function() {
    return {
        restrict: 'E',
        compile: function(element, attrs) {
            var type = attrs.type || 'text';
            var required = attrs.hasOwnProperty('required') ? "required='required'" : "";
            var htmlText = '<div class="control-group">' +
                '<label class="control-label" for="' + attrs.formId + '">' + attrs.label + '</label>' +
                    '<div class="controls">' +
                    '<input type="' + type + '" class="input-xlarge" id="' + attrs.formId + '" name="' + attrs.formId + '" ' + required + '>' +
                    '</div>' +
                '</div>';
            element.replaceWith(htmlText);
        }
    };
})

Tried to use the solution proposed by Misko, but in my situation, some attributes, which needed to be merged into my template html, were themselves directives.

Unfortunately, not all of the directives referenced by the resulting template did work correctly. I did not have enough time to dive into angular code and find out the root cause, but found a workaround, which could potentially be helpful.

The solution was to move the code, which creates the template html, from compile to a template function. Example based on code from above:

    angular.module('formComponents', [])
  .directive('formInput', function() {
    return {
        restrict: 'E',
        template: function(element, attrs) {
           var type = attrs.type || 'text';
            var required = attrs.hasOwnProperty('required') ? "required='required'" : "";
            var htmlText = '<div class="control-group">' +
                '<label class="control-label" for="' + attrs.formId + '">' + attrs.label + '</label>' +
                    '<div class="controls">' +
                    '<input type="' + type + '" class="input-xlarge" id="' + attrs.formId + '" name="' + attrs.formId + '" ' + required + '>' +
                    '</div>' +
                '</div>';
             return htmlText;
        }
        compile: function(element, attrs)
        {
           //do whatever else is necessary
        }
    }
})

The above answers unfortunately don't quite work. In particular, the compile stage does not have access to scope, so you can't customize the field based on dynamic attributes. Using the linking stage seems to offer the most flexibility (in terms of asynchronously creating dom, etc.) The below approach addresses that:

<!-- Usage: -->
<form>
  <form-field ng-model="formModel[field.attr]" field="field" ng-repeat="field in fields">
</form>
// directive
angular.module('app')
.directive('formField', function($compile, $parse) {
  return { 
    restrict: 'E', 
    compile: function(element, attrs) {
      var fieldGetter = $parse(attrs.field);

      return function (scope, element, attrs) {
        var template, field, id;
        field = fieldGetter(scope);
        template = '..your dom structure here...'
        element.replaceWith($compile(template)(scope));
      }
    }
  }
})

I've created a gist with more complete code and a writeup of the approach.


Here's what I ended up using.

I'm very new to AngularJS, so would love to see better / alternative solutions.

angular.module('formComponents', [])
    .directive('formInput', function() {
        return {
            restrict: 'E',
            scope: {},
            link: function(scope, element, attrs)
            {
                var type = attrs.type || 'text';
                var required = attrs.hasOwnProperty('required') ? "required='required'" : "";
                var htmlText = '<div class="control-group">' +
                    '<label class="control-label" for="' + attrs.formId + '">' + attrs.label + '</label>' +
                        '<div class="controls">' +
                        '<input type="' + type + '" class="input-xlarge" id="' + attrs.formId + '" name="' + attrs.formId + '" ' + required + '>' +
                        '</div>' +
                    '</div>';
                element.html(htmlText);
            }
        }
    })

Example usage:

<form-input label="Application Name" form-id="appName" required/></form-input>
<form-input type="email" label="Email address" form-id="emailAddress" required/></form-input>
<form-input type="password" label="Password" form-id="password" /></form-input>

참고URL : https://stackoverflow.com/questions/10629238/customizing-the-template-within-a-directive

반응형