Lightningコンポーネント動的生成サンプルコンポーネント

## はじめに

[Spring '15のリリースノート](http://docs.releasenotes.salesforce.com/en-us/spring15/release-notes/rn_lightning_components.htm)によると、新しいLightningコンポーネントが幾つも使えるようになっているようです。果たして今度はドキュメントに掲載されているコンポーネントはすべて動くのでしょうか。

ということで、今回は好きなパラメーターを指定して簡単にコンポーネントを生成できるコンポーネントを用意しました。

## 動作サンプル

ソースは後述しますのでまずは動作です。テンプレートから好きなサンプルを選んで、

![スクリーンショット 2014-12-30 0.23.59.png](https://qiita-image-store.s3.amazonaws.com/0/44645/f672fb42-4d49-708f-788d-3742d87c946b.png)

パラメーターを調整して「`Create Component!`」ボタンを押すと、タグでは生成できなかった`ui:inputTextArea`コンポーネントができました。

![スクリーンショット 2014-12-30 0.25.07.png](https://qiita-image-store.s3.amazonaws.com/0/44645/ce091fb5-9f78-79b6-75b7-89813de64549.png)

今度は別のテンプレートを選ぶと、Spring '15から公開のSpinnerコンポーネントもできました（実際にはアニメーションします）。

![スクリーンショット 2014-12-30 0.23.34.png](https://qiita-image-store.s3.amazonaws.com/0/44645/993bfa99-8efd-40b9-e55c-ae300006cd68.png)

outputRichTextAreaコンポーネントは`<br />`タグに対応していないこともわかります（[ソース](https://github.com/forcedotcom/aura/blob/master/aura-components/src/main/components/ui/outputRichText/outputRichTextHelper.js)を見ると、`SUPPORTED_HTML_TAGS`になぜか`"br"`がないことがわかります）。

![スクリーンショット 2014-12-30 0.25.24.png](https://qiita-image-store.s3.amazonaws.com/0/44645/65737139-3598-5e45-1ab8-6b117d128131.png)

## ソース

こちらがコンポーネントのソースです。基本的に[コンポーネントの動的生成によるui:messageのラッパー](http://qiita.com/twk/items/e2c8f061795b7a377353)で紹介した`newComponentAsync`メソッドを呼んでいるだけです。

```xml:ComponentPlayground.cmp
<aura:component implements="force:appHostable">   
    <form>
        template: <select aura:id="template" onchange="{!c.changeTemplate}">
        <option aura:id="defaultTemplate" value='{
                       "componentDef": "markup://",
                       "attributes": {
                       "values": {
                       
                       }
                       }
                       }'>Empty</option>
        <option value='{
                       "componentDef": "markup://ui:button",
                       "attributes": {
                       "values": {
                       "label": "hello", 
                       "buttonTitle": "world"
                       }
                       }
                       }'>button (no event)</option>
        <option value='{
                       "componentDef": "markup://ui:message",
                       "attributes" : {
                       "values" : {
                       "title": "hello", 
                       "severity": "error", 
                       "closable": true
                       }
                       }
                       }'>ui:message</option>
        <option value='{
                       "componentDef": "markup://ui:inputTextArea",
                       "attributes": {
                       "values": {
                       "value": "hello\ntext area world."
                       }
                       }
                       }'>inputTextArea</option>
        <option value='{
                       "componentDef": "markup://ui:outputTextArea",
                       "attributes": {
                       "values": {
                       "value": "hello\ntext area world."
                       }
                       }
                       }'>outputTextArea</option>
        <option value='{
                       "componentDef": "markup://ui:outputRichText",
                       "attributes": {
                       "values": {
                       "value": "hello&lt;br />\n&lt;b>Rich&lt;/b> text area world."
                       }
                       }
                       }'>outputRichText</option>
        <option value='{
                       "componentDef": "markup://ui:inputSecret",
                       "attributes": {
                       "values": {
                       }
                       }
                       }'>inputSecret</option>
        <option value='{
                       "componentDef": "markup://ui:outputURL",
                       "attributes": {
                       "values": {
                       "label": "example link", "value": "http://example.com/"
                       }
                       }
                       }'>outputURL</option>
        <option value='{
                       "componentDef": "markup://ui:outputPhone",
                       "attributes": {
                       "values": {
                       "label": "phone", "value": "0120-000-000"
                       }
                       }
                       }'>outputPhone</option>
        <option value='{
                       "componentDef": "markup://ui:image",
                       "attributes": {
                       "values": {
                       "src": "https://secure.sfdcstatic.com/common/assets/img/logo-tagline-company.png"
                       }
                       }
                       }'>image</option>
        <option value='{
                       "componentDef": "markup://ui:spinner"
                       }'>spinner</option>
        </select><br />
        <textarea aura:id="textarea" style="width: 500px; height:200px;"></textarea><br />
        <ui:button press="{!c.createComponent}" label="Create Component!" />
    </form>
    
    <div aura:id="placeholder" style="border: solid 1px;"></div>
    <ul>
        <li><a href="/auradocs/reference.app#reference?descriptor=ui:button&amp;defType=component">aura docs</a></li>
	    <li><a href="https://github.com/forcedotcom/aura/tree/master/aura-components/src/main/components/ui">github aura components/ui</a></li>
    </ul>
</aura:component>
```

```js:ComponentPlayground.js
({
    changeTemplate: function(component, event, helper) {
       	var select = component.get('template');
        var value = select.getElement().value;

        var textarea = component.get('textarea');
        textarea.getElement().value = JSON.stringify(JSON.parse(value), null, "\t");
    },
    createComponent: function(component, event, helper) {
        var textarea = component.get('textarea');
        var value = textarea.getElement().value;
        
        try {
            var componentDef = JSON.parse(value);
            console.log(value, componentDef);
            $A.componentService.newComponentAsync(
                component,
                function(newComponent) {
                    console.log('component created');
                    var placeholder = component.find('placeholder');
                    placeholder.set('v.body', newComponent);
                },
                componentDef
            );            
        } catch (e) {
            $A.error(e);
            $A.trace();
        }
    }
})
```

## おわりに

何か面白いコンポーネントがあったらテンプレートに足したいので教えてください。

とはいいつつ、実際のところはコンポーネントファイルにタグで書くとは思うので、このコンポーネントが実用的なのかはかなり怪しいところですが、色々なコンポーネントの表示を試したい時、タグの記述を更新してプレビューを再読み込みするよりもこちらに適当に記載して生成した方が早い場合もあるかもしれません。