.Js dosyasına göre açısal yönerge templateUrl


85

Birkaç farklı yerde kullanılacak açısal bir yönerge oluşturuyorum. Yönergenin kullanıldığı uygulamanın dosya yapısını her zaman garanti edemem, ancak kullanıcıyı directive.jsve directive.html(gerçek dosya adlarını değil) aynı klasöre koymaya zorlayabilirim .

Sayfa değerlendirir zaman directive.js, bu gördüğü templateUrlkendine göreli olarak. Dosyayı templateUrlgöreceli olarak ayarlamak mümkün mü directive.js?

Ya da sadece şablonu direktifin içine dahil etmeniz önerilir.

Farklı koşullara dayalı olarak farklı şablonlar yüklemek isteyebileceğimi düşünüyorum, bu nedenle, web sitesini güncellemek yerine göreceli bir yol kullanmayı tercih ederim. directive.js


4
Veya, şablonlarınızı AngularJs'in şablon önbelleğinde önbelleğe alacağı js'ye dönüştürmek için grunt-html2js'yi kullanabilirsiniz. Bu, açısal-ui adamlarının yaptığı şeydir.
Beyers

Harika fikir Beyers, grunt-html2js hakkında bir bilgim yoktu. Kontrol edecek.
pedalpete

Yanıtlar:


76

Şu anda çalıştırılan komut dosyası dosyası her zaman komut dosyaları dizisindeki son dosya olacaktır, böylece yolunu kolayca bulabilirsiniz:

// directive.js

var scripts = document.getElementsByTagName("script")
var currentScriptPath = scripts[scripts.length-1].src;

angular.module('app', [])
    .directive('test', function () {
        return {
            templateUrl: currentScriptPath.replace('directive.js', 'directive.html')
        };
    });

Komut dosyasının adının ne olduğundan emin değilseniz (örneğin, birden çok komut dosyasını tek bir komut dizisine topluyorsanız), şunu kullanın:

return {
    templateUrl: currentScriptPath.substring(0, currentScriptPath.lastIndexOf('/') + 1) 
        + 'directive.html'
};

Not : Bir kapatmanın kullanıldığı durumlarda, currentScript'in doğru zamanda değerlendirilmesini sağlamak için kodunuz dışarıda olmalıdır, örneğin:

// directive.js

(function(currentScriptPath){
    angular.module('app', [])
        .directive('test', function () {
            return {
                templateUrl: currentScriptPath.replace('directive.js', 'directive.html')
        };
    });
})(
    (function () {
        var scripts = document.getElementsByTagName("script");
        var currentScriptPath = scripts[scripts.length - 1].src;
        return currentScriptPath;
    })()
);

2
Oh, şimdi bu çok havalı! Ne yazık ki, bu js dosyalarımı paketlemek ve küçültmekle bozulur, değil mi? Ayrıca, neden 'şu anda yürütülmekte olan komut dosyası her zaman sonuncu dosyadır'? Tüm betik dosyalarının global kapsamda yüklendiği izlenimi altındaydım.
pedalpete

1
Tarayıcı bir <script>etiketle karşılaştığında , sayfayı oluşturmaya devam etmeden hemen önce onu yürütür, bu nedenle genel bir komut dosyası kapsamında son <script>etiket her zaman son etikettir.
Alon Gubkin

1
Ayrıca, bu küçültmeyi bozmamalı, ancak paketlemede kırılmalı, bu yüzden buna bir çözüm ekledim
Alon Gubkin

Sanırım ne demek istediğini anlıyorum. Sayfadaki her şeyi tek bir komut dosyası etiketi içinde yüklediğimi varsayıyordunuz. Durum böyle değil, ama bunun etrafında çalışabilirim. Harika ve yaratıcı bir cevap için teşekkürler!
pedalpete

1
Komut dosyasının adını değiştirmek yerine, path = currentScriptPath.split("/"); path.pop(); path.push("directive.html");bunun dosya adlarına bağımlılığı yoktur ve "directive.js", "/directive.js" ve "path / to / directive.js" yi destekler. Kod golf yarışması, bunları tek bir ifadede birleştirmektir (splice, vb. Kullanarak).
Nathan MacInnes

6

Direktiflere farklı zamanlarda farklı şablonlar sağlamak istediğinizi söylediğiniz gibi, neden şablonun kendisinin bir öznitelik olarak yönergeye aktarılmasına izin vermiyorsunuz?

<div my-directive my-template="template"></div>

O zaman $compile(template)(scope)direktifin içinde olduğu gibi bir şey kullanın .


Cevap vermediğim için üzgünüm. Yönerge nesnesi içinde birden çok şablonum olduğunu mu öneriyorsunuz? ve sonra $compileyöntemi hangi şablon geçirilirse ona yönlendirin. $compileYine de kullanmak zorunda kalabilirim, bu yüzden bu iyi bir öneri olabilir.
pedalpete

4

Alon Gubkin'in cevabına ek olarak, komut dosyasının yolunu saklamak ve yönergeye enjekte etmek için Anında Çağrılan İşlev İfadesi kullanarak bir sabit tanımlamayı öneririm:

angular.module('app', [])

.constant('SCRIPT_URL', (function () {
    var scripts = document.getElementsByTagName("script");
    var scriptPath = scripts[scripts.length - 1].src;
    return scriptPath.substring(0, scriptPath.lastIndexOf('/') + 1)
})())

.directive('test', function(SCRIPT_URL) {
    return {
        restrict :    'A',
        templateUrl : SCRIPT_URL + 'directive.html'
    }
});

3

Bu kod, route.js adlı bir dosyadadır.

Aşağıdakiler benim için işe yaramadı:

var scripts = document.getElementsByTagName("script")
var currentScriptPath = scripts[scripts.length-1].src;
var baseUrl = currentScriptPath.substring(0, currentScriptPath.lastIndexOf('/') + 1);

şu yaptı:

var bu2 = document.querySelector("script[src$='routes.js']");
currentScriptPath = bu2.src;
baseUrl = currentScriptPath.substring(0, currentScriptPath.lastIndexOf('/') + 1);

Testim, need to lazy load angular kullanımıyla ilgili şu bloga dayanıyor: http://ify.io/lazy-loading-in-angularjs/

required.js bir requireConfig önyükleme başlatır

requireConfig, açısal bir app.js oluşturur

açısal app.js, rotalarımı başlatıyor.js

Bir revel web çerçevesi ve asp.net mvc tarafından sunulan aynı koda sahiptim. Revel'de document.getElementsByTagName ("script"), gerekli bootstrap js dosyama giden bir yol üretti ve route.js'mi DEĞİL. ASP.NET MVC'de, hata ayıklama oturumları sırasında oraya yerleştirilen Visual Studio'nun enjekte edilen Tarayıcı Bağlantısı komut dosyası öğesine bir yol üretti.

bu benim çalışma rotaları.js kodum:

define([], function()
{
    var scripts = document.getElementsByTagName("script");
    var currentScriptPath = scripts[scripts.length-1].src;
    console.log("currentScriptPath:"+currentScriptPath);
    var baseUrl = currentScriptPath.substring(0, currentScriptPath.lastIndexOf('/') + 1);
    console.log("baseUrl:"+baseUrl);
    var bu2 = document.querySelector("script[src$='routes.js']");
    currentScriptPath = bu2.src;
    console.log("bu2:"+bu2);
    console.log("src:"+bu2.src);
    baseUrl = currentScriptPath.substring(0, currentScriptPath.lastIndexOf('/') + 1);
    console.log("baseUrl:"+baseUrl);
    return {
        defaultRoutePath: '/',
            routes: {
            '/': {
                templateUrl: baseUrl + 'views/home.html',
                dependencies: [
                    'controllers/HomeViewController',
                    'directives/app-style'
                ]
            },
            '/about/:person': {
                templateUrl: baseUrl + 'views/about.html',
                dependencies: [
                    'controllers/AboutViewController',
                    'directives/app-color'
                ]
            },
            '/contact': {
                templateUrl: baseUrl + 'views/contact.html',
                dependencies: [
                    'controllers/ContactViewController',
                    'directives/app-color',
                    'directives/app-style'
                ]
            }
        }
    };
});

Bu, Revel'den çalışırken konsol çıktım.

currentScriptPath:http://localhost:9000/public/ngApps/1/requireBootstrap.js routes.js:8
baseUrl:http://localhost:9000/public/ngApps/1/ routes.js:10
bu2:[object HTMLScriptElement] routes.js:13
src:http://localhost:9000/public/ngApps/1/routes.js routes.js:14
baseUrl:http://localhost:9000/public/ngApps/1/ 

Yaptığım bir başka güzel şey de, gerekli yapılandırmadan yararlanmak ve içine bazı özel yapılandırmalar koymak. yani ekle

customConfig: { baseRouteUrl: '/AngularLazyBaseLine/Home/Content' } 

daha sonra aşağıdaki kodu route.js'nin içinden kullanarak alabilirsiniz.

var requireConfig = requirejs.s.contexts._.config;
console.log('requireConfig.customConfig.baseRouteUrl:' + requireConfig.customConfig.baseRouteUrl); 

bazen bir baseurl'yi önceden tanımlamanız gerekir, bazen de dinamik olarak oluşturmanız gerekir. Durumunuz için seçiminiz.


2

Bazıları bunu biraz "hacky" olarak önerebilir, ancak bence bunu yapmanın tek bir yolu kalana kadar her şey hileli olacak.
Bunu yaparken de çok şansım oldu:

angular.module('ui.bootstrap', [])
  .provider('$appUrl', function(){
    this.route = function(url){
       var stack = new Error('dummy').stack.match(new RegExp(/(http(s)*\:\/\/)[^\:]+/igm));
       var app_path = stack[1];
       app_path = app_path.slice(0, app_path.lastIndexOf('App/') + 'App/'.length);
         return app_path + url;
    }
    this.$get = function(){
        return this.route;
    } 
  });

Ardından, modülü uygulamaya ekledikten sonra kodu bir uygulamada kullanırken.
Bir uygulama yapılandırma işlevinde:

.config(['$routeProvider', '$appUrlProvider', function ($routeProvider, $appUrlProvider) {

    $routeProvider
        .when('/path:folder_path*', {
            controller: 'BrowseFolderCntrl',
            templateUrl: $appUrlProvider.route('views/browse-folder.html')
        });
}]);

Ve bir uygulama denetleyicisinde (gerekirse):

var MyCntrl = function ($scope, $appUrl) {
    $scope.templateUrl = $appUrl('views/my-angular-view.html');
};

Yeni bir javascript hatası oluşturur ve yığın izlemesini çıkarır. Daha sonra tüm url'leri ayrıştırır (arayan hat / karakter numarası hariç).
Daha sonra, kodun çalıştığı geçerli dosya olacak dizideki ilkini çekebilirsiniz.

Bu ayrıca, kodu merkezileştirmek ve ardından [1]çağıran dosyanın konumunu almak için dizideki ikinci ( ) öğesini çıkarmak istiyorsanız yararlıdır.


Bu yavaş, hileli ve gerçekten kullanmak oldukça can sıkıcı olacak, ancak yenilik için +1!
Nathan MacInnes

Dediğim gibi, bunu yapmanın bir yolu yok, bu yüzden herhangi bir yöntemin artıları ve eksileri olacak. Uygulamanın nerede yaşadığını bulmak için uygulama yüklemesi başına yalnızca bir kez kullanıldığı için gerçekten herhangi bir performans sorunu bulamadım. Ayrıca, kullanımı oldukça kolay, bunu bir angularjs sağlayıcısına saran tam kodu göstermedim ... cevabımı güncelleyebilir.
dan richardson

0

Birkaç kullanıcının belirttiği gibi, statik dosyaları oluştururken ilgili yollar yardımcı olmaz ve bunu kesinlikle tavsiye ederim.

Angular'da $ templateCache adında , şablon dosyalarını aşağı yukarı önbelleğe alan ve bir dahaki sefere bu açısal, gerçek bir istekte bulunmak yerine, önbelleğe alınmış sürümü sağlayan şık bir özellik vardır . Bu, onu kullanmanın tipik bir yoludur:

module = angular.module('myModule');
module.run(['$templateCache', function($templateCache) {
$templateCache.put('as/specified/in/templateurl/file.html',
    '<div>blabla</div>');
}]);
})();

Yani bu şekilde hem göreli URL sorununu çözersiniz hem de performans kazanırsınız.

Elbette ayrı şablon html dosyalarına sahip olma fikrini seviyoruz (tepki vermenin aksine), bu nedenle yukarıdakilerin tek başına bir faydası yok. Burada, tüm şablon html dosyalarını okuyabilen ve yukarıdakiler gibi bir js oluşturabilen yapı sistemi geliyor.

Grunt, gulp, webpack için birkaç html2js modülü vardır ve bunların arkasındaki ana fikir budur. Ben şahsen gulp'u çok kullanıyorum, bu yüzden özellikle gulp-ng-html2js'i çok beğeniyorum çünkü tam olarak bunu çok kolay yapıyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.