2015-06-18 17 views
46

Cho một mô hình cho một bộ phận trang, trong đó có nhiều lĩnh vực và sẽ được dân cư với dữ liệu đó như thế này:động Hợp phần lựa chọn trong Angular2

{ 
    "fields": [ 
     { 
      "id": 1, 
      "type": "text", 
      "caption": "Name", 
      "value": "Bob" 
     }, 
     { 
      "id": 2, 
      "type": "bool", 
      "caption": "Over 24?", 
      "value": 0 
     }, 
     { 
      "id": 3, 
      "type": "options", 
      "options" : [ "M", "F"], 
      "caption": "Gender", 
      "value": "M" 
     } 
    ] 
} 

Tôi muốn có một phần phần chung mà không biết về các kiểu trường khác nhau mà nó có thể bọc, để tránh rất nhiều logic có điều kiện trong mẫu phần và để tạo các khung nhìn/thành phần kiểu trường mới bằng cách thả vào một tệp khép kín thay vì phải sửa đổi một thành phần riêng biệt.

Lý tưởng của tôi là cho bộ chọn Thành phần đủ cụ thể để tôi có thể thực hiện việc này bằng cách chọn phần tử trong mẫu của Thành phần gốc dựa trên giá trị thuộc tính được liên kết với mô hình. Ví dụ: (tha thứ bất kỳ vấn đề cú pháp như tôi mã này trong cửa sổ SO, phần chính phải chú ý đến là chọn trên BooleanComponent.ts

SectionComponent.ts

@Component({ 
    selector: 'my-app' 
}) 
@View({ 
    template: ` 
     <section> 
      <div *ng-for="#field of fields"> 
       <field type="{{field.type}}"></field> 
      </div> 
     </section> 
    `, 
    directives: [NgFor] 
}) 
class SectionComponent { 
    fields: Array<field>; 
    constructor() { 
     this.fields = // retrieve section fields via service 
    } 
} 

FieldComponent.ts:

// Generic field component used when more specific ones don't match 
@Component({ 
    selector: 'field' 
}) 
@View({ 
    template: `<div>{{caption}}: {{value}}</div>` 
}) 
class FieldComponent { 
    constructor() {} 
} 

BooleanComponent.ts:

// specific field component to use for boolean fields 
@Component({ 
    selector: 'field[type=bool]' 
}) 
@View({ 
    template: `<input type="checkbox" [id]="id" [checked]="value==1"></input>` 
}) 
class BooleanComponent { 
    constructor() {} 
} 

... và theo thời gian tôi muốn thêm đồng mới mponents để cung cấp các mẫu và hành vi đặc biệt cho các loại trường cụ thể khác hoặc thậm chí là các trường có chú thích nhất định, v.v.

Điều này không hoạt động vì bộ chọn thành phần phải là tên phần tử đơn giản (trong alpha.26 và alpha.27 tại ít nhất). Nghiên cứu của tôi về các cuộc hội thoại github dẫn tôi tin rằng hạn chế này đã được thư giãn, nhưng tôi không thể xác định xem những gì tôi muốn làm thực sự sẽ được hỗ trợ.

Ngoài ra, tôi đã thấy một DynamicComponentLoader được đề cập, mặc dù bây giờ tôi không thể tìm thấy ví dụ mà tôi nghĩ là trên hướng dẫn angular.io. Mặc dù vậy, tôi không biết làm thế nào nó có thể được sử dụng để tự động tải một thành phần mà nó không biết tên hoặc tiêu chí phù hợp cho.

Có cách nào để hoàn thành mục tiêu tách các thành phần chuyên biệt khỏi cha mẹ bằng cách sử dụng kỹ thuật tương tự với những gì tôi đã thử hoặc một số kỹ thuật khác mà tôi không biết trong Angular 2?

CẬP NHẬT 2015-07-06

http://plnkr.co/edit/fal9OA7ghQS1sRESutGd?p=preview

Tôi nghĩ rằng nó tốt nhất để hiển thị các lỗi tôi chạy vào một cách rõ ràng hơn. Tôi đã bao gồm một plunk với một số mẫu mã, mặc dù chỉ có đầu tiên của 3 lỗi này sẽ được hiển thị, như là một trong những khối khác để bạn chỉ có thể hiển thị ra một tại một thời điểm. Tôi đã khó mã hóa để có được khoảng # 2 và # 3 cho thời điểm này.

  1. Cho dù chọn của tôi trên BooleanComponent là selector: 'field[type=bool]' hoặc selector: '[type=bool]', tôi nhận được một đống lỗi từ góc như

    Component 'BooleanComponent' chỉ có thể có một bộ chọn thành phần, nhưng đã '[type = bool]

  2. <field [type]="field.type"></field> không ràng buộc giá trị field.type của tôi với thuộc tính type, nhưng cung cấp cho tôi lỗi này (Rất may hiển thị trong alpha 28.Trong phiên bản alpha 26 trước đây, tôi đã không hoạt động âm thầm). Tôi có thể loại bỏ lỗi này khi thêm thuộc tính type vào FieldComponent và BooleanComponent phái sinh và nối nó với bộ sưu tập thuộc tính @Component, nhưng tôi không cần nó cho bất cứ thứ gì trong các thành phần.

    Không thể liên kết với 'loại' vì nó không phải là một tài sản bí quyết của các yếu tố 'trường' và không có chỉ thị phù hợp với một tài sản tương ứng

  3. tôi buộc phải liệt kê FieldComponent và BooleanComponent trong danh sách chỉ thị của chú thích Xem Phần của tôi, hoặc chúng sẽ không được tìm thấy và áp dụng. Tôi đọc các thảo luận thiết kế từ nhóm Angular, nơi họ đưa ra quyết định có ý thức này để ủng hộ nhân chứng để giảm thiểu sự va chạm với các chỉ thị trong các thư viện bên ngoài, nhưng nó phá vỡ toàn bộ ý tưởng về các thành phần mà tôi đang cố gắng đạt được.

Tại thời điểm này, tôi đang đấu tranh để xem lý do tại sao Angular2 thậm chí còn có lựa chọn. Thành phần cha mẹ đã phải biết những thành phần con nào sẽ có, nơi chúng sẽ đi và dữ liệu nào chúng cần. Các bộ chọn là hoàn toàn không cần thiết tại thời điểm này, nó cũng có thể là một quy ước phù hợp với tên lớp. Tôi không thấy sự trừu tượng giữa các thành phần tôi cần phải tách chúng ra.

Do những hạn chế này trong khả năng của khung công tác Angular2, tôi đang tạo lược đồ đăng ký thành phần của riêng mình và đặt chúng qua DynamicComponentLoader, nhưng tôi vẫn rất tò mò muốn xem bất kỳ phản hồi nào cho những người đã tìm thấy tốt hơn cách để thực hiện điều này.

+1

Great câu hỏi. Tôi đang chạy vào cùng một vấn đề. Tôi đã tìm thấy rằng trong alpha-34, chúng tôi sẽ nhận được một giải pháp một phần. Bất kỳ bộ chọn nào cũng sẽ được phép cho các thành phần. Bạn có thể kiểm tra tại đây https://github.com/angular/angular/pull/3336. Tuy nhiên, vấn đề lựa chọn động vẫn chủ đề. Tôi muốn xem giải pháp của bạn với DynamicComponentLoader, nếu có thể. –

+0

Câu hỏi hay, chúng tôi đang cố gắng tránh có một swtich lớn, hoặc ngNếu chặn trên trang. – nycynik

Trả lời

0

Tôi mất một lúc, nhưng tôi thấy những gì bạn đang cố gắng làm. Về cơ bản tạo ra một thư viện hình thức bắt buộc cho ng2, giống như góc-formly. Những gì bạn đang cố gắng làm không được đề cập trong tài liệu, nhưng có thể được yêu cầu. Các tùy chọn hiện tại có thể được tìm thấy under annotations from lines 419 - 426.

Giải pháp này sẽ chọn quá mức dẫn đến một số điểm tích cực sai, nhưng hãy thử.

Thay đổi <field type="{{field.type}}"></field>-<field [type]="field.type"></field>

Sau đó chọn cho thuộc tính:

@Component({ 
    selector: '[type=bool]' 
}) 
+0

Thật không may, không thay đổi cú pháp mẫu cũng như công cụ chọn được đề xuất thực sự hoạt động. Tôi đã cập nhật câu hỏi ban đầu để cung cấp chi tiết về lý do tại sao họ không làm như vậy. – DannyMeister

+2

Và cảm ơn vì đã đề cập đến hình thức góc cạnh, mà tôi chưa từng gặp trước đây. Có một số điểm tương đồng với những gì tôi muốn hoàn thành, nhưng tôi vẫn muốn các thành phần của tôi hoạt động giống như các thành phần chuẩn angular2 với ngoại lệ nhỏ mà tôi có nhiều quyền kiểm soát hơn đối với chế độ xem được sử dụng để đại diện cho mô hình dữ liệu của tôi. – DannyMeister

0

Tôi đoán bạn có thể sử dụng Query/ViewQuery và QueryList để tìm tất cả các yếu tố, đăng ký thay đổi của QueryList và các yếu tố lọc theo bất kỳ thuộc tính , smth. như thế này:

constructor(@Query(...) list:QueryList<...>) { 
    list.changes.subscribe(.. filter etc. ..); 
} 

Và nếu bạn muốn liên kết với loại, bạn nên làm điều đó như thế này:

<input [attr.type]="type"/> 
1
  1. Khi lỗi nói, một thành phần phải có một bộ chọn độc đáo. Nếu bạn muốn liên kết hành vi thành phần với bộ chọn thuộc tính như với [type='bool'], bạn phải sử dụng các chỉ thị. Sử dụng selector='bool-field' cho số BoolComponent của bạn.

  2. Khi lỗi nói, thành phần chung <field> của bạn không có thuộc tính type để liên kết. Bạn có thể sửa lỗi bằng cách thêm biến thành viên đầu vào: @Input() type: string;

  3. Bạn muốn ủy quyền mẫu thành phần cho một thành phần duy nhất nhận thuộc tính type.Chỉ cần tạo thành phần chung đó và các thành phần khác sử dụng nó sẽ chỉ phải cung cấp nó, không phải là các thành phần của nó.

Ví dụ: http://plnkr.co/edit/HUH8fm3VmscsK3KEWjf6?p=preview

@Component({ 
    selector: 'generic-field', 
    templateUrl: 'app/generic.template.html' 
}) 
export class GenericFieldComponent { 
    @Input() 
    fieldInfo: FieldInfo; 
} 

sử dụng mẫu:

<div> 
    <span>{{fieldInfo.caption}}</span> 

    <span [ngSwitch]="fieldInfo.type"> 
    <input *ngSwitchWhen="'bool'" type="checkbox" [value]="fieldInfo.value === 1"> 
    <input *ngSwitchWhen="'text'" type="text" [value]="fieldInfo.value"> 
    <select *ngSwitchWhen="'options'" type="text" [value]="fieldInfo.value"> 
     <option *ngFor="let option of fieldInfo.options" > 
     {{ option }} 
     </option> 
    </select> 
    </span> 
</div> 
+0

Đây chính là loại giải pháp mà tôi đã nói tôi đang cố gắng tránh. Tôi không muốn chỉ định trách nhiệm của việc tạo mọi thành phần cho một thành phần đơn lẻ với logic điều kiện. Tôi không biết tại thời gian biên dịch tất cả các thành phần có thể sẽ là gì. Khách hàng của tôi có thể thả các thành phần mới. Tôi đã có một ví dụ làm việc bằng cách sử dụng DynamicComponentLoader, mà đã không được chấp nhận và tôi chưa cập nhật. Đối với những người cần một giải pháp năng động hơn là một giải pháp tĩnh như câu trả lời được đề xuất này, tôi khuyên bạn nên kiểm tra xem câu hỏi và câu trả lời trùng lặp được liên kết có giúp bạn không. – DannyMeister

+0

Nếu khách hàng của bạn có thể rơi vào thành phần mới, tôi cho rằng họ cũng sẽ cung cấp một mẫu. Nếu vậy, bạn có thể sử dụng [innerHtml] để chèn mẫu. Nếu bạn muốn xây dựng thành phần mới trong thời gian chạy, bạn nên xem xét trình biên dịch góc (https://angular.io/docs/ts/latest/api/compiler/TemplateCompiler-class.html) – cghislai

+0

Trình biên dịch mẫu có vẻ thú vị. Tôi sẽ xem xét liệu tôi có bao giờ cần quay trở lại Angular từ Aurelia (làm cho tất cả điều này dễ dàng hơn nhiều, btw!). – DannyMeister

Các vấn đề liên quan