2016-06-29 18 views
4

角度プロジェクトでを使用するにはangular-selectizeを使用しています。 Selectize.jsアイテムのレンダリング角度ディレクティブ

は、私がSelectize.js' renderオプションを使用していますSelectize.jsセレクタにカスタムアイテムを使用するには:アバターは非同期動作とカスタムディレクティブです

render: { 
    item: function(item, escape) { 
    var avatar = '<div>' + 
     '<span avatars="\'' + escape(item._id) +'\'" class="avatars">' + 
     '</span>' + 
     escape(item.nick) + 
     '</div>'; 
    var compiledAvatar = $compile(avatar)($rootScope); 
    $timeout(); 
    return compiledAvatar.html(); 
    }, 

問題がrender.itemということです

この関数は、出力が、としてHTML文字列を期待:

  • returninの方法はありませんg render.itemメソッドによってレンダリングされたか、または "$compile ed" HTML文字列が同期方法で期待通りに出力されます。
  • 私は、彼らがすでにDOMに追加されたとき、後でその項目の要素をレンダリングする方法がわかりません。

$ compileが呼び出されますが、返される文字列は期待されるコンパイル結果ではなく、$ compileの非同期性のためにコンパイル前の文字列になります。

+0

angle-selectizeのgithubの問題として追加されました:https://github.com/machineboy2045/angular-selectize/issues/142 – atfornes

+0

これは、推奨する方法ではないかもしれませんが、あなたが望む行動? – Pytth

+0

@Pythth、約束がどのように役立つのかわかりません、 'render.item'関数は約束ではなくhtml' string'を返す必要があることに注意してください。この問題の約束をどのように使用するかに関するアイデアをお寄せください。ありがとう! – atfornes

答えて

0

この回答は、次のような違いを持つ@gregoriによって投票回答に基づいています:キャッシュをレンダリングSelectize.js

  1. を考慮してください。 Selectize.jsの標準的な動作は、アイテムがレンダリング関数によって返されるようにキャッシュされ、変更が行われていないことです。いくつかの要素を追加および削除した後、レンダリングキャッシュを更新しないと、キャッシュされたバージョンと変更されなかったバージョンが表示されます。
  2. ランダムなIDを使用して、DOMから操作する要素を識別します。
  3. コンパイルが

最初に行われた際に知ってウォッチャーを使用して、我々はselectize.jsを変更するためのメソッドを定義キャッシュレンダリング:次に

scope.selectorCacheUpdate = function(key, value, type){ 

    var cached = selectize.renderCache[type][key]; 

    // update cached element 
    var newValue = angular.element(cached).html(value); 

    selectize.renderCache[type][key] = newValue[0].outerHTML; 

    return newValue.html(); 
}; 

を次のように、レンダリング関数が定義されています:

function renderAvatar(item, escape, type){ 

    // Random id used to identify the element 
    var randomId = Math.floor(Math.random() * 0x10000000).toString(16); 

    var avatar = 
    '<div id="' + randomId + '">' + 
     '<span customAvatarTemplate ...></span>' + 
     ... 
    '</div>'; 

    var compiled = $compile(avatar)($rootScope); 

    // watcher to see when the element has been compiled 
    var destroyWatch = $rootScope.$watch(
    function(){ 
     return compiled[0].outerHTML; 
    }, 
    function (newValue, oldValue){ 
     if(newValue !== oldValue){ 

     var elem = angular.element(document.getElementById(randomId)); 

     var rendered = elem.scope().selectorCacheUpdate(item._id, compiled.html(), type); 

     // Update DOM element 
     elem.html(rendered); 

     destroyWatch(); 
     } 
    } 
); 
}); 

return avatar; 

}

注:

config = { 
    ... 
    render: { 
    item: function(i,e){ 
     return renderAvatar(i, e, 'item'); 
    }, 
    option: function(i,e){ 
     return renderAvatar(i, e, 'option'); 
    } 
    }, 
    ... 
} 
レンダリングキャッシュのための鍵は、我々はselectize構成オブジェクトに機能をレンダリングselectizeとしてこの機能を追加し、最後に、この場合には、 _id

selectize項目のvalueFieldです

詳細については、この解決策が、この質問を動機付けるアプリケーションにどのように追加されたかを参照してください。https://github.com/P2Pvalue/teem/commit/968a437e58c5f1e70e80cc6aa77f5aefd76ba8e3

1

はひとつのアイデアが最も推奨角度の方法ではありませんDOM操作を使用することですが、私はあなたの非同期呼び出しをシミュレートするためにworking on this plunker.second one with custom directive and randomized data to simulate your compiled avatar.

それを得た、私はngResourceを使用しています。私のレンダリング関数は、文字列"<div class='compiledavatar'>Temporary Avatar</div>"と特別なクラスマークcompiledavatarを返します。 2〜2回は、要素を選択すると一時アバターが表示されます。 ngResourceが終了したら、クラスcompiledavatarの要素を探し、htmlをダウンロードしたものに置き換えます。ここでは、完全なコードは次のとおりです。

var app = angular.module('plunker', ['selectize', 'ngResource']); 

app.controller('MainCtrl', function($scope, $resource, $document) { 
    var vm = this; 
    vm.name = 'World'; 
    vm.$resource = $resource; 
    vm.myModel = 1; 
    vm.$document = $document; 

    vm.myOptions = [{ 
    id: 1, 
    title: 'Spectrometer' 
    }, { 
    id: 2, 
    title: 'Star Chart' 
    }, { 
    id: 3, 
    title: 'Laser Pointer' 
    }]; 

    vm.myConfig = { 
    create: true, 
    valueField: 'id', 
    labelField: 'title', 
    delimiter: '|', 
    placeholder: 'Pick something', 
    onInitialize: function(selectize) { 
     // receives the selectize object as an argument 
    }, 
    render: { 
     item: function(item, escape) { 
     var label = item.title; 
     var caption = item.id; 
     var Stub = vm.$resource('mydata', {}); 
     // This simulates your asynchronous call 

     Stub.get().$promise.then(function(s) { 
      var result = document.getElementsByClassName("compiledavatar") 
      angular.element(result).html(s.compiledAvatar); 

      // Once the work is done, remove the class so next time this element wont be changed 
      // Remove class 
      var elems = document.querySelectorAll(".compiledavatar"); 
      [].forEach.call(elems, function(el) { 
       el.className = el.className.replace(/compiledavatar/, ""); 
      }); 

     }); 

     return "<div class='compiledavatar'>Temporary Avatar</div>" 
     } 
    }, 
    // maxItems: 1 
    }; 
}); 

私はちょうどplunker mydataでファイルを作成したJSON APIをシミュレートするには:

{ 
    "compiledAvatar": "<div><span style='display: block; color: black; font-size: 14px;'>an avatar</span></div>" 
    } 

もちろん、あなたのコンパイルされた関数はあなたに別の何かすべての呼び出しを返す必要があります。私は原理を実証するために私に同じことを与えます。

は、データがカスタムディレクティブmy-customerが含まれます:あなたの動的なコードがAgularディレクティブがある場合は、よりよい解決策を見ることができるように、また

は、ここでカスタムディレクティブでsecond plunkerとランダム化されたデータをあります

[{ 
    "compiledAvatar": "<div><span style='display: block; color: black; font-size: 14px;'>an avatar #1 <my-customer></my-customer></span></div>" 
    }, 
    { 
    "compiledAvatar": "<div><span style='display: block; color: black; font-size: 14px;'>an avatar #2 <my-customer></my-customer></span></div>" 
    }, 
(...) 

ディレクティブは次のように定義されます

app.directive('myCustomer', function() { 
    return { 
    template: '<div>and a custom directive</div>' 
    }; 
}); 

とアプリの主な違いは、あなたヘクタールでありますHTMLを置き換えるときに$ compileを追加すると、テキストはAn avatar #(number) and a custom directiveと表示されます。私はjsonの値の配列を取得し、単純なランダムを使用して値を選択します。 HTMLが置き換えられたら、クラスを削除するので、次に最後に追加された要素だけが変更されます。

Stub.query().$promise.then(function(s) { 
     var index = Math.floor(Math.random() * 10); 
     var result = document.getElementsByClassName("compiledavatar") 
     angular.element(result).html($compile(s[index].compiledAvatar)($scope)); 

     // Remove class 
     var elems = document.querySelectorAll(".compiledavatar"); 
     [].forEach.call(elems, function(el) { 
     el.className = el.className.replace(/compiledavatar/, ""); 
     }); 
}); 

また、私はselectize libraryを見て、htmlと同様に約束を返すことはできません。レンダリングによって返された値に置き換えます。これが、私が後で検索して更新するクラスを持つ一時的な文字列のルートに行った理由です。 それが役立つかどうか教えてください。

+0

不幸にも、このソリューションにはいくつかの問題があり、レンダリングされた要素のSelectize.jsキャッシュによって完全には機能しません。この問題の解決方法については、次の回答をご覧ください。http://stackoverflow.com/a/38640167/4928558 – atfornes

+0

@atfornesテストでキャッシュの問題は発生しませんでしたが、ソリューションの改善と私たちとの共有に感謝します。 – Gregori

関連する問題