2015-06-27 13 views
1

我試圖構建一個小部件來呈現UI上的任意數據(JavaScript對象)。數據的模式由json schema文件定義。而且模型必須是雙向綁定的,因爲我想使用這個小部件來輸入/顯示數據。angularjs指令根據任意js構建小部件json模式對象

指令是否是正確的方法?有沒有人可以給我一些線索來實現這一目標?

+0

存在已經是一個開源項目,處理這樣的事情:http://schemaform.io/ – Claies

回答

1

是的,指令是正確的。你可以看到評論中提到的angular-schema-form正在使用指令。

如果您想創建自己的指令。請看下面的演示或此jsfiddle

帶註釋的例子可能不是最好的,因爲在那裏你不需要數據的雙向綁定。 但它應該給你一個想法如何可以工作。

代碼是如何工作的?

  1. 它遍歷schema.items.properties並創建ng-model/ng-restrict模板,並將其添加到模板中的所有綁定。
  2. 循環完成後,$compile服務正在將當前範圍添加到模板。
  3. 用編譯模板替換html。

angular-schema-form代碼相比,該演示可能非常基本,但它更易於理解,並且更易於根據需要進行修改。

angular.module('demoApp', []) 
 
    .controller('mainController', MainController) 
 
    .directive('awDisplayJsonView', DisplayJsonView) 
 
    .directive('awDateParser', DateParser); 
 

 
/** 
 
* Translates unix time stamp into readable dates 
 
* from model/view & view/model 
 
*/ 
 
function DateParser() { 
 
    return { 
 
    require: 'ngModel', 
 
    link: function(scope, element, attrs, ngModelController) { 
 
     ngModelController.$parsers.push(function(data) { 
 
     //convert data from view format to model format 
 
     return new Date(data).getTime(); //converted 
 
     }); 
 

 
     ngModelController.$formatters.push(function(data) { 
 
     //convert data from model format to view format 
 
     return new Date(parseInt(data)).toUTCString(); //converted return UTC 
 
     }); 
 
    } 
 
    } 
 
} 
 

 
function MainController() { 
 
    angular.extend(this, { 
 
     /*jsonView: { 
 
      "text": { // name of model 
 
       type: "input", 
 
       label: "Two way binded input", 
 
      } 
 
     },*/ 
 
     jsonModel: [{ 
 
      "id": 1, 
 
      "name": "Test User", 
 
      "text": "I am a comment.", 
 
      "date": "1435427542904", 
 
     }, { 
 
      "id": 2, 
 
      "name": "Antother User", 
 
      "text": "I am the second comment.", 
 
      "date": "1435427605064", 
 
     }], 
 

 
     jsonSchema: { 
 
      "$schema": "http://json-schema.org/draft-04/schema#", 
 
      "title": "Comments", 
 
      "type": "array", 
 
      "items": { 
 
       "title": "Comment", 
 
       "type": "object", 
 
       "properties": { 
 
        "id": { 
 
         "description": "The unique identifier for a comment.", 
 
         "type": "number", 
 
         "format": "hidden" // not sure if this is the right place 
 
        }, 
 
        "name": { 
 
         "title": "Name", 
 
         "type": "string" 
 
        }, 
 
        "text": { 
 
         "title": "Comment", 
 
         "type": "string" 
 
        }, 
 
        "date": { 
 
         "title": "Date (format y/m/d hh:mm:ss GMT)", 
 
         "type": "string", 
 
         "format": "date-time" 
 
        } 
 
       }, 
 
       "required": [ 
 
        "id", 
 
        "name", 
 
        "text"] 
 
      } 
 
     } 
 
    }); 
 
} 
 

 
function DisplayJsonView($compile) { 
 
    var templatesObj = { 
 
     string: function (hidden) { 
 
      return $('<input/>') 
 
       .attr('type', hidden) 
 
       .addClass('form-control'); 
 
     }, 
 
     checkbox: function (hidden) { 
 
      return $('<input/>') 
 
       .attr('type', hidden || 'checkbox') 
 
       .addClass('form-control'); 
 
     }, 
 
     number: function(hidden) { 
 
      return $('<input/>') 
 
       .attr('type', hidden) 
 
       .addClass('form-control'); 
 
     } 
 
    }; 
 
    
 
    function render(schema, model, index) { 
 
     var outTemplate = $(document.createDocumentFragment()), 
 
      tempTmpl, hidden; // temporary template, hidden input 
 
     
 
     angular.forEach(schema.items.properties, function (prop, key) { 
 
      //console.log(key, prop.type, prop.format, templatesObj[prop.type]); 
 
      hidden = prop.format == 'hidden'? 'hidden': null; 
 
      tempTmpl = templatesObj[prop.type](hidden); // get template based on type 
 
      tempTmpl.attr({ 
 
       'ng-model': 
 
        'model[' + index + '].' + key, // add current model 
 
       'ng-required': schema.items.required.indexOf(key) != -1 // check if it is required 
 
      }); 
 
      
 
      if (prop.format == 'date-time') 
 
       tempTmpl.attr('aw-date-parser', ''); // add directive if we have a date 
 
       
 
      outTemplate.append($('<div/>').addClass('form-group') 
 
       .append(!hidden ? $('<label/>').text(prop.title || key) : null) //add label if not hidden 
 
       .append(tempTmpl)); 
 
     }); 
 
     //console.log(model, outTemplate); 
 
     return outTemplate; 
 
    } 
 
    return { 
 
     restrict: 'EA', 
 
     scope: { 
 
      //view: '=', // angular schema form does implement this 
 
      model: '=', 
 
      schema: '=' 
 
     }, 
 
     template: '<div>{{schema |json:2}}</div>', 
 
     link: function (scope, element, attrs) { 
 
      var out = $('<form/>'); 
 
      
 
      angular.forEach(scope.model, function(item, index) { 
 
       //console.log(item); 
 
       out.append(render(scope.schema, item, index)); 
 
      }); 
 
      var compiled = $compile(out)(scope); 
 
      //console.log(scope.model, scope.schema); 
 
      element.replaceWith(compiled); 
 
     } 
 
    }; 
 
} 
 

 
DisplayJsonView.$inject = ['$compile'];
body { 
 
    padding: 0.5em; 
 
} 
 
.form-group { 
 
    padding-bottom: 0.25em; 
 
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/> 
 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.1/angular.js"></script> 
 
<div ng-app="demoApp" ng-controller="mainController as ctrl"> 
 
    <h3>Comments list with schema json directive</h3> 
 
    <form name="form" aw-display-json-view="" data-model="ctrl.jsonModel" data-schema="ctrl.jsonSchema" ng-cloak=""></form> 
 
    <div ng-cloak> 
 
    {{form|json}} 
 
    {{ctrl.jsonModel}} 
 
    </div> 
 
</div>

+0

感謝Awolf!似乎angular-schema-form可以爲我節省很多工作。我會花一些時間來研究它。 – ricky