2

私は、Angular を使用して Node.js API サーバーの周りに SPA を作成する基幹業務アプリケーションに取り組んでいます。状態マシンの ui-router の原因と、URL を埋め込む直感的な方法を使用することにしましたが、ディレクティブ内で動的 URL を作成するときに、ちょっとした問題が発生しました。

データ グリッドに jQuery Datatables をディレクティブとして使用していますが、「fnRender」を使用して生成されたアクション リンクは、「ui-sref」をそれぞれの「href」リンクにコンパイルしていないようです。ディレクティブ コードは次のとおりです。

app.directive('datatable', function ($http) {
  return {
    restrict: 'A',
    link: function ($scope, $elem, attrs) {
        var responsiveHelper;
        var breakpointDefinition = {
            tablet: 1024,
            phone : 480
        };
        var options = {
            bDeferRender: true,
            sPaginationType: "full_numbers",
            oLanguage: {
                sEmptyTable: "No records returned",
                sSearch: "<span>Search:</span> ",
                sInfo: "Showing <span>_START_</span> to <span>_END_</span> of <span>_TOTAL_</span> entries",
                sLengthMenu: "_MENU_ <span>entries per page</span>",
                sProcessing: "Loading..."
            },
            sDom: "lfrtip",
            oColVis: {
                buttonText: "Change columns <i class='icon-angle-down'></i>"
            },
            oTableTools: {
                sSwfPath: "js/plugins/datatable/swf/copy_csv_xls_pdf.swf"
            },
            bAutoWidth     : false,
            fnPreDrawCallback: function () {
                if (!responsiveHelper) {
                    responsiveHelper = new ResponsiveDatatablesHelper($elem, breakpointDefinition);
                }
            },
            fnRowCallback  : function (nRow, aData, iDisplayIndex, iDisplayIndexFull) {
                responsiveHelper.createExpandIcon(nRow);
            },
            fnDrawCallback : function (oSettings) {
                responsiveHelper.respond();
            }
        };
        if (typeof $scope.dtOptions !== 'undefined') {
            angular.extend(options, $scope.dtOptions);
        }
        if (attrs['dtoptions'] === undefined) {
            for (property in attrs) {
                switch (property) {
                    case 'sajaxsource':
                        options['sAjaxSource'] = attrs[property];
                    break;
                    case 'sajaxdataprop':
                        options['sAjaxDataProp'] = attrs[property];
                    break;
                }
            }
        } else {
            angular.extend(options, $scope[attrs['dtoptions']]);
        }   

        if (typeof options['sAjaxSource'] === 'undefined') {
            throw "Ajax Source not defined! Use sajaxsource='/api/v1/*'";
        }
        if (typeof options['fnServerData'] === 'undefined') {
            options['fnServerData'] = function (sSource, aoData, resultCb) {
                $http.get(sSource, aoData).then(function (result) {
                    resultCb(result.data);
                });
            };
        }
        options.aoColumnDefs = [];
        $elem.find('thead th').each(function() {
            var colattr = angular.element(this).data();
            if (colattr.mdata) {
                if (colattr.mdata.indexOf("()") > 1) {
                    var fn = $scope[colattr.mdata.substring(0, colattr.mdata.length - 2)];
                    if (typeof fn === 'function') {
                        options.aoColumnDefs.push({
                            mData: fn,
                            sClass: colattr.sclass,
                            aTargets: [colattr.atargets]
                        });     
                    } else {
                        throw "mData function does not exist in $scope.";
                    }
                } else {
                    options.aoColumnDefs.push({
                        mData: colattr.mdata,
                        sClass: colattr.sclass,
                        bVisible: colattr.bvisible,
                        aTargets: [colattr.atargets]
                    }); 
                }
            } else {
                if (colattr.fnrender.indexOf("()") > 1) {
                    var fn = $scope[colattr.fnrender.substring(0, colattr.fnrender.length - 2)];
                    if (typeof fn === 'function') {
                        options.aoColumnDefs.push({
                            fnRender: fn,
                            sClass: colattr.sclass,
                            aTargets: [colattr.atargets]
                        });     
                    } else {
                        throw "fnRender function does not exist in $scope.";
                    }
                } else {
                    options.aoColumnDefs.push({
                        fnRender: function (oObj) {
                            return "<a tooltip class='btn' title='View' ui-sref=\""+colattr.tag+".show({slug:\'"+oObj.aData._id+"\'})\"><center class=\"icon-search\"></center></a>";
                        },
                        sClass: colattr.sclass,
                        bVisible: colattr.bvisible,
                        aTargets: [colattr.atargets]
                    }); 
                }
            }
        });
        $elem.dataTable(options);
        $(".dataTables_length select").wrap("<div class='input-mini'></div>").chosen({disable_search_threshold: 9999999 });
    }
  }
});

これは複雑にならずに実行され、次のアンカー タグも生成されます。

<a ui-sref="organisation.show({slug:'527a44c02aa9ce3a1c3fbc17'})"></a> 

ただし、ui-router はそれをそれぞれの状態 URL にコンパイルしません。問題は何ですか?見逃したかもしれない設定はありますか?

ありがとう

4

2 に答える 2

3

データ テーブル内で他のディレクティブまたは式を使用していますか? Angular は、生成している HTML をコンパイルする機会がないように見えるため、これらも機能しないと思います。

これはuiSref、ディレクティブを正しく記述することとは関係ありません。ベスト プラクティスに関して言えば、このディレクティブにはコードが多すぎます複数のネストされたディレクティブとストレートな HTML に分解することを検討する必要があります。トランスクルージョンについて学び、ディレクティブ コントローラーを使用してネストされたディレクティブを実行することに時間を費やすことをお勧めします。

于 2013-11-15T11:05:51.747 に答える
1

ベスト プラクティスはさておき、私はこの問題に遭遇して自分で解決しました。DataTables は Angular のイベント ループの外で DOM を変更しているため、ui-sref 属性はコンパイルされません。これは簡単な修正です: 各行が作成されるたびに $compile を呼び出す必要があります。

これが私の(はるかに単純な)ディレクティブです:

function datatable($compile) {
    return {
        restrict: "A",
        link: (scope, elem, attrs) => {


            // THE IMPORTANT BIT
            scope.options.createdRow = function (row) {
                $compile(row)(scope);
            };


            var api = elem.DataTable(scope.options);
            var handleUpdates = function (newData) {
                var data = newData || null;
                if (data) {
                    api.clear();
                    api.rows.add(data).draw();
                }
            };
            scope.$watch("options.data", handleUpdates, true);
        },
        scope: { options: "=" }
    };
}
于 2014-06-17T12:24:06.507 に答える