Estoy creando una directiva angular que se usará en algunas ubicaciones diferentes. No siempre puedo garantizar la estructura de archivos de la aplicación en la que se usa la directiva, pero puedo obligar al usuario a poner directive.js
y directive.html
(no los nombres de archivo reales) en la misma carpeta.
Cuando la página evalúa directive.js
, considera templateUrl
que es relativo a sí misma. ¿Es posible establecer templateUrl
que sea relativo al directive.js
archivo?
O se recomienda simplemente incluir la plantilla en la propia directiva.
Creo que es posible que desee cargar diferentes plantillas en función de diferentes circunstancias, por lo que preferiría poder usar una ruta relativa en lugar de actualizar la directive.js
javascript
angularjs
path
pedalear
fuente
fuente
Respuestas:
El archivo de script que se está ejecutando actualmente será siempre el último en la matriz de scripts, por lo que puede encontrar fácilmente su ruta:
// 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') }; });
Si no está seguro de cuál es el nombre del script (por ejemplo, si está empaquetando varios scripts en uno), use esto:
return { templateUrl: currentScriptPath.substring(0, currentScriptPath.lastIndexOf('/') + 1) + 'directive.html' };
Nota : En los casos en que se utiliza un cierre, su código debe estar fuera para garantizar que el código actual se evalúe en el momento correcto, como por ejemplo:
// 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; })() );
fuente
<script>
etiqueta, la ejecuta inmediatamente antes de continuar renderizando la página, por lo que en un ámbito de script global, la última<script>
etiqueta es siempre la última.path = currentScriptPath.split("/"); path.pop(); path.push("directive.html");
hacerlo. Esto no tiene ninguna dependencia en los nombres de archivo y admite "directive.js", "/directive.js" y "ruta / a / directive.js". La competencia de golf de código consiste en combinar estos en una sola declaración (usando empalmes, et al).Como dijo que quería proporcionar diferentes plantillas en diferentes momentos para las directivas, ¿por qué no permitir que la plantilla en sí se pase a la directiva como un atributo?
<div my-directive my-template="template"></div>
Luego use algo como
$compile(template)(scope)
dentro de la directiva.fuente
$compile
método a la plantilla que se pase? Puede que tenga que usarlo de$compile
todos modos, por lo que puede ser una buena sugerencia.Además de la respuesta de Alon Gubkin , sugeriría definir una constante usando una Expresión de función invocada inmediatamente para almacenar la ruta del script e inyectarla en la directiva:
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' } });
fuente
Este código está en un archivo llamado route.js
Lo siguiente no funcionó para mí:
var scripts = document.getElementsByTagName("script") var currentScriptPath = scripts[scripts.length-1].src; var baseUrl = currentScriptPath.substring(0, currentScriptPath.lastIndexOf('/') + 1);
lo siguiente hizo:
var bu2 = document.querySelector("script[src$='routes.js']"); currentScriptPath = bu2.src; baseUrl = currentScriptPath.substring(0, currentScriptPath.lastIndexOf('/') + 1);
Mi prueba se basa en el siguiente blog sobre el uso de require to lazy load angular: http://ify.io/lazy-loading-in-angularjs/
require.js genera un bootstrap requireConfig
requireConfig genera una aplicación angular.js
angular app.js engendra mis rutas.js
Tuve el mismo código servido por un framework web revel y asp.net mvc. En revel document.getElementsByTagName ("script") produjo una ruta a mi archivo obligatorio bootstrap js y NO a mis rutas.js. en ASP.NET MVC produjo una ruta al elemento de secuencia de comandos de enlace de navegador inyectado de Visual Studio que se coloca allí durante las sesiones de depuración.
este es mi código de trabajo route.js:
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' ] } } }; });
Esta es la salida de mi consola cuando se ejecuta desde Revel.
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/
Otra cosa buena que he hecho es aprovechar la configuración requerida y poner algunas configuraciones personalizadas en ella. es decir, agregar
customConfig: { baseRouteUrl: '/AngularLazyBaseLine/Home/Content' }
luego puede obtenerlo usando el siguiente código desde el interior de routes.js
var requireConfig = requirejs.s.contexts._.config; console.log('requireConfig.customConfig.baseRouteUrl:' + requireConfig.customConfig.baseRouteUrl);
a veces necesitas definir una baseurl por adelantado, a veces necesitas generarla dinámicamente. Tu elección para tu situación.
fuente
Algunos pueden sugerir que es un poco "hacky", pero creo que hasta que solo haya una forma de hacerlo, cualquier cosa va a ser hacky.
También tuve mucha suerte haciendo esto:
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; } });
Luego, al usar el código en una aplicación después de incluir el módulo en la aplicación.
En una función de configuración de la aplicación:
.config(['$routeProvider', '$appUrlProvider', function ($routeProvider, $appUrlProvider) { $routeProvider .when('/path:folder_path*', { controller: 'BrowseFolderCntrl', templateUrl: $appUrlProvider.route('views/browse-folder.html') }); }]);
Y en un controlador de aplicación (si es necesario):
var MyCntrl = function ($scope, $appUrl) { $scope.templateUrl = $appUrl('views/my-angular-view.html'); };
Crea un nuevo error de JavaScript y extrae el seguimiento de la pila. Luego analiza todas las URL (excluyendo la línea de llamada / número de caracteres).
A continuación, puede extraer el primero de la matriz, que será el archivo actual donde se ejecuta el código.
Esto también es útil si desea centralizar el código y luego extraer el segundo (
[1]
) en la matriz, para obtener la ubicación del archivo de llamadafuente
Como han señalado varios usuarios, las rutas relevantes no son útiles al crear archivos estáticos, y recomiendo encarecidamente hacerlo.
Hay una característica ingeniosa en Angular llamada $ templateCache , que más o menos almacena en caché los archivos de plantilla, y la próxima vez que angular requiera uno, en lugar de realizar una solicitud real, proporciona la versión en caché. Esta es una forma típica de usarlo:
module = angular.module('myModule'); module.run(['$templateCache', function($templateCache) { $templateCache.put('as/specified/in/templateurl/file.html', '<div>blabla</div>'); }]); })();
De esta manera, ambos abordan el problema de las URL relativas y ganan en rendimiento.
Por supuesto, nos encanta la idea de tener archivos html de plantilla separados (en contraste con reaccionar), por lo que lo anterior por sí solo no es bueno. Aquí viene el sistema de compilación, que puede leer todos los archivos html de plantilla y construir un js como el anterior.
Hay varios módulos html2js para grunt, gulp, webpack, y esta es la idea principal detrás de ellos. Personalmente, uso mucho gulp, por lo que me gusta particularmente gulp-ng-html2js porque hace exactamente esto con mucha facilidad.
fuente