I am using HTML5 mode in AngularJS and I have a <base href="/some/base/path" /> defined in the <head> section of my HTML file.
What is the best way of reading this value in AngularJS? I understand that you can just read this HTML tag with jQuery, but something tells me this is not the most elegant way of doing it.
What I want to achieve
I would like to compose URL dynamically from controller. For instance, current page is http://localhost/myapp/some/custom/page/ where http://localhost/myapp is a base url. I want to build http://localhost/myapp/another/page url in angular controller by doing the following
baseUrl + `/another/page`
AngularJS doesn't really have any functions for extracting attributes from tags. However, there are a workaround. But the pure javascript way I added at the bottom of the answer might be the best solution for you.
Let's say you change the base tag:
<base ng-controller="MyController" data-href="/some/base/path">
In your controller you can do the following to access data-href:
app.controller('MyController', function ($scope, $attrs) {
console.log($attrs.href); // Prints '/some/base/path'
});
Or you can do it in pure javascript with:
var url = document.getElementsByTagName('base')[0].getAttribute('href');
Related
I have an angularjs 1.5.8 application created using Jhipster.
For my website I want to make a HTML and JAVASCRIPT editor. Need to allow user to write HTML Code but JAVASCRIPT also.
Using this library I know I can achieve the follow.
https://github.com/incuna/angular-bind-html-compile
1: Bind HTML Code.
2: Bind Angular code if present in HTML
Eg: <h1>{{$scope.test}}</h1>
Would render correct value in the scope.
But what about something like this in the html
<script>
console.log($scope);
</script>
I get a $scope not defined error, somehow the $scope value is not available in the script tag.
If anyone curious that why I need to do this because we want to provide users of the application to create there own Angularjs Forms.
I solved using ng-include, here is the example source.
I wanted to do two things.
1: Make ng-include work from a scope variable which will contain html and javascript.
2: In the included string if I have a script tag I wanted it to render correct in the ng-include.
To achieve the #1 I did the following.
Used $templateCache service.
Sample code.
$templateCache.put('template-form', vm.html + vm.script);
For point #2
I made sure the script tag is structured in the following way.
<script>
(function() {
'use strict';
angular.module('myApp').controllerProvider.register('AppTemplateController',AppTemplateController);
AppTemplateController.$inject = ['$scope'];
function AppTemplateController($scope){
// WRITE YOUR CODE IN THIS CONTROLLER
// YOU CAN WRITE YOUR VARIABLES/FUNCTIONS HERE.
// MAKE SURE TO CALL THE method "vm.submitForm", to submit your form and pass the form object.
};
})();
</script>
This way you can inject a controller.
My requirement was very very specific to my projecct, I am not sure if others who did not face this issue even would understand what I am talking about. But for those who do face it, I hope you it helpful
I retrieve the code of an HTML page from a server thanks to a rest service and I want integrate the html code into an empty template
.controller('TestController', ['$scope' ,'$rootScope' , '$sce' , function ($scope ,$rootScope,$sce) {
var restHtml =$rootScope.test; //contains <div>Test</div>
$scope.showHtml= $sce.trustAsHtml(restHtml );
}]);
The template
<div ng-bind-html="showHtml"></div> <!-- didn't work and i want a solution without integrate my html code into a existing div -->
Thank you
Ideally DOM manipulations should not happen in the controller, directives should be used for them.
To answer your question, you could compile the html into your tag. Get the html, find the element you want to insert the html in and use compile to do it. A good example of compile.
I have an angularjs application where I need to update a few meta tags (for fb sharing) based on data that the controller gets from a service.
Right now I am doing something like this in my ItemController when the controller gets the data from the service:
angular.element('head').find('#metaFbImage').attr('content', $scope.item.imageUrl);
This is really BAD and I want to do this in a directive. But I cannot figure out a nice way to do it. So far I have two alternatives:
1) A directive on the head tag. When the ItemController gets the data from the service I want to call a function in the directive that changes the meta tags. How can a controller call a function from a different scope ( is outside ItemController)?
2) A service that is injected into ItemController, and the service changes the meta tags. This is a slightly better (and workable) solution. But is it OK to manupulate DOM elements in a service in cases like these?
EDIT: So I chose to refactor this into using $rootScope in the controller, and watching $rootScope in a directive on the head. I feel that this is somewhere between acceptable and bad practice. Any ideas?
use this approach.
Create a Service (Factory) with parameters such as
`
angular.module("myApp").factory("OGFactory", function(){
var OGFactory = {
title : "",
description : "",
...
};
return OGFactory;
});
set your ng-app on the <html> element as <html ng-app="your_app_name"> so that the <head> block can access items within your ng-app.
inject OGFactory into your Controller. also inject it into your $run block and set it on $rootScope as $rootScope.OGFactory = OGFactory.
After your controller has done whatever it needs to do (if anything is async), set OGFactory.title and OGFactory.description.
In your <head> section, include meta tags such as: <meta name="og:title" content="{{OGFactory.title}}">
The controller will set the OGFactory properties and the rootScope will reflect them.
Note, however, that Facebook does not wait for Javascript to be done processing in order to fetch the page results, so your {{title}} will just look like (literally)
"{{title}}" unless you use a service like prerender.io. This method works great with prerender.
I'm working with a form that needs to bind HTML to a Rich Text Editor. The best way to store this HTML content would be an HTML file.
I can't quite figure out how to load an HTML template from a file and assign it to a variable.
Directives seem to do be able to do this when working with templateUrl. Was wondering if this there is any low level api in angular to achieve the same thing inside of a controller
Using $templateRequest, you can load a template by it’s URL without having to embed it into your HTML page. If the template is already loaded, it will be taken from the cache.
app.controller('testCtrl', function($scope, $templateRequest, $sce, $compile){
// Make sure that no bad URLs are fetched. You can omit this if your template URL is
// not dynamic.
var templateUrl = $sce.getTrustedResourceUrl('nameOfTemplate.html');
$templateRequest(templateUrl).then(function(template) {
// template is the HTML template as a string
// Let's put it into an HTML element and parse any directives and expressions
// in the code. (Note: This is just an example, modifying the DOM from within
// a controller is considered bad style.)
$compile($("#my-element").html(template).contents())($scope);
}, function() {
// An error has occurred
});
});
Be aware that this is the manual way to do it, and whereas in most cases the preferable way would be to define a directive that fetches the template using the templateUrl property.
All templates are loaded into a cache. There is an injectable $templateCache service you can use to get access to the templates:
app.controller('testCtrl', function($scope, $templateCache){
var template = $templateCache.get('nameOfTemplate.html');
});
I am not building a single-page application, but rather a "traditional" site that uses AngularJS in places. I've hit the following problem (using 1.3.0-beta.6):
Standard, working anchor links:
Link text
... [page content]
<a id="foo"></a>
<h1>Headline</h1>
[more content]
That works fine. Now I introduce a template partial somewhere:
<script type="text/ng-template" id="test-include.html">
<p>This text is in a separate partial and inlcuded via ng-include.</p>
</script>
which is invoked via:
<div ng-include="'test-include.html'"></div>
The partial is included properly, but the anchor link no longer works. Clicking on "Link text" now changes the displayed URL to /#/foo rather than /#foo and the page position does not change.
My understanding is that using ng-include implicitly tells Angular that I want to use the routes system and overrides the browser's native anchor link behavior. I've seen recommendations to work around this by changing my html anchor links to #/#foo, but I can't do that for other reasons.
I don't intend to use the routes system - I just want to use ng-include without it messing with browser behavior. Is this possible?
The reason is that angular overrides the behavior of standard HTML tags which include <a> also. I'm not sure when this change happened because angular v1.0.1 works fine with this.
You should replace the href attribute with ngClick as:
<a ng-click="scroll()">Link text</a>
And in a controller so:
function MyCtrl($scope, $location, $anchorScroll) {
$scope.scroll = function() {
$location.hash('foo');
$anchorScroll();
};
};
Demo: http://jsfiddle.net/HB7LU/3261/show/
Or simply use double hash as:
<a href='##foo'>Link text</a>
Demo: http://jsfiddle.net/HB7LU/3262/show/
Update: I did not know that you want no modification in HREF. But you can still achieve the desired result by overriding the existing a directive as:
myApp.directive('a', function() {
return {
restrict: 'E',
link: function(scope, element) {
element.attr('href', '#' + element.attr('href'));
}
};
});
Demo: http://jsfiddle.net/HB7LU/3263/
My understanding is that using ng-include implicitly tells Angular
that I want to use the routes system and overrides the browser's
native anchor link behavior. I've seen recommendations to work around
this by changing my html anchor links to #/#foo, but I can't do that
for other reasons.
Routing system is defined in a separate module ngRoute, so if you did not injected it on your own - and I am pretty sure you did not - it is not accessible at all.
The issue is somehow different here.
ng-include depends on: $http, $templateCache, $anchorScroll, $animate, $sce. So make use of ng-include initiate all these services.
The most natural candidate to investigate would be $anchorScroll. The code of $anchorScroll does not seem to do any harm, but the service depends on $window, $location, $rootScope. The line 616 of $location says:
baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
So basically the base href is set to '', if it was no set before.
Now look HERE - from BalusC answer :
As to using named anchors like , with the tag
you're basically declaring all relative links relative to it,
including named anchors. None of the relative links are relative to
the current request URI anymore (as would happen without the
tag).
How to mitigate the issue?
I do not have much time today, so cannot test it myself, but what I would try to check as the first option is to hook up to '$locationChangeStart' event and if the new url is of #xxxxxx type just prevent the default behaviour and scroll with $anchorScroll native methods instead.
Update
I think this code should do the work:
$scope.$on("$locationChangeStart", function (event, next, current) {
var el, elId;
if (next.indexOf("#")>-1) {
elId = next.split("#")[1];
el = document.getElementById(elId);
if(el){
// el.scrollIntoView(); do not think we need it
window.location.hash = "#" + elId;
event.preventDefault();
}
}
});
This is the best solution, and works in recent versions of Angular:
Turn off URL manipulation in AngularJS
A lot late to the party but I found that adding a simple target="_self" fixes it.
Link
Rather than applying the angular application to the entire page, you can isolate the application to just the places you want to perform an ng-include. This will allow links outside the scope of the application to retain their normal functionality, while allowing links within the application to be handled as desired.
See this plunkr:
http://plnkr.co/edit/hOB7ixRM39YZEhaz0tfr?p=preview
The plunkr shows a link outside the app that functions as normal, and a link within the app that is handled using an overriding a directive to restore normal functionality. HTML5 mode is enabled to retain 'standard' URLs (rather than 'hashbang' [without the bang!] URLs).
You could equally run the whole of the page within the app, but I thought it would be worth demonstrating how to isolate angular to certain parts of the page in any case.