Fetching HTML in Angular - angularjs

I am getting started with Angular, and I want to get HTML template from a file using JavaScript, I don't want to use ng-include or any other directive as I don't really have an html to play with, I have only JavaScript file with data rendered from REST service and I need to send HTML output to the page I am in, so I don't really have any existing elements in the DOM.
So how do I get HTML from another file and use it just from JavaScript, in an Angular way?

I think you should use directive and as James point out use the $compile.
You can look some doc https://docs.angularjs.org/guide/compiler
If for any reason you don't want to do that, I can put an exemple of a really BAD angular code I use on my app to show the CGU (an HTML from another domain).
Note that we use jQuery, and that's not a good thing in Angular world.
$http({
method: 'GET',
url: 'URL_HTML'
}).success(function (data, status, headers, config) {
var html_from_server = $.parseHTML(data);
data = $(html_from_server.find('#container'));//look for the content of an ID.
$('#content_cgu').html(data.html());// get an element on our page and replace the html content
});

Take a look at $compile - it sounds like that's what you're looking for. You can take the html from your service and compile it to work in your AngularJS application.

Let me rephrase it. How do I get HTML from another page and store it in a variable inside my JS file using Angular? What do I do? var returnedHTML = ???
Straightforward solution:
var returnedHTML;
var url = 'http://www.google.com';
$http.get(url, { cache: $templateCache }).then(function(result){
returnedHTML = result.data;
});

I was just dealing with this today. I think your question was misunderstood.
You simply include an ng-include into your code like so:
ng-include="'https://en.wikipedia.org/wiki/Special:Random'"
Angular will display your URL as directly in the page.

Related

How to refresh iframe url?

I am creating an app using ionic in which I am displaying a URL using iframe.
This is the HTML code:
<iframe id="myFrame" width="100%" height={{iframeHeight}}>
This is the angular js:
$scope.iframeHeight = window.innerHeight;
document.getElementById("myFrame").src = value['url'];
Everything is working, however when I make changes on the site from the backend and refresh the app the new changes are not appearing in the app.
The thing you are doing in your code is not a valid way of doing it. You are manipulating DOM using native method that will not run digest cycle, you need to run it manually by doing $scope.$apply(). That will solve your problem but generally you should not do DOM manipulation from controller which is considered as BAD practice. Rather I'd suggest you to use angular two way binding feature. Assign url in scope scope variable and add that on iframe tag using ng-src="{{url}}" so that src URL will be updated by angular and as url get updated iframe will load content from src URL in it.
HTML
<iframe id="myFrame" width="100%" ng-src="{{url}}" height={{iframeHeight}}>
Code
$scope.url = "http://example.com"
As you change scope variable in the controller the the src of iframe will also gets change and iframe will reload the content.
Update
To solve caching issue you need to append current date time to you url that will every time make a new URL and it won't be cached by the browser. Something like $scope.url = "http://example.com?dummyVar="+ (new Date()).getTime() by using this it will never harm your current behavior, only you need to append dummyVar with current time value which would be always unique.
$scope.url = "http://example.com?dummyVar="+ (new Date()).getTime()
Refreshing didn't work for me with timestamp as in Pankaj Parkar's answer, so I solved it in a bit of a hacky way, which just toggles ng-if element off and on again, and forces iframe to load.
Template:
<iframe ng-if="!vm.isRefreshing"></iframe>
Controller:
refreshIframe() {
this.isRefreshing = true;
$timeout(() => {
this.isRefreshing = false;
}, 50);
}
As #pankajparkar suggested in his answer, I'd suggest you using angular 2-way data binding.
In addition to that, you need to wrap the urls with $sce.trustAsResourceUrl function in order to your iframe to work.
<iframe id="myFrame" width="100%" ng-src="{{url}}" height={{iframeHeight}}>
And
$scope.url = $sce.trustAsResourceUrl("http://example.com");

Angularjs Style/highlight code block within ng-bind-html

In an effort to learn Angualr.js, I'm trying to collect a Wordpress post, using the plugin WP REST API and display it on a template in its correct format. I've got the post displaying the correct way using sanitize and ng-bind-html.
However, there are code blocks that I had originally highlighted (using WP Code Prettify) within the post. For example:
The question is how do I get the original post to look just like the image above, using ng-bind-html? Or is there another, more efficient way to do this?
You should try using $sce to mark the post content as trusted.
Example:
.controller('CtrlName', function($scope, $http, $sce) {
$http.get('wp-json/pages/pageSlug').success(function(res){
$scope.page = res;
$scope.page.content = $sce.trustAsHtml(res.content);
});
})

How can I dynamically set templates without messy query parameters in angular ui-router?

I'm building an artist portfolio web app where the artist can create a 'project' which consists of a series of content pieces (mostly images at this point) which can then be put in an order and the artist can choose between different preset layouts. I'm using angular and node + express. I'm struggling to find a good way to dynamically set templates. The only functional scheme i've devised so far is to put the template name in a query parameter in the url like this.
ui-sref="webapp/project/photo?template=vertical"
then in ui-router it's relatively simple to set the template using state params
templateUrl : function (stateparams) {
return 'templates/' + stateparams.template + '.html';
},
Although it's functional I don't like this mostly because it creates messy urls and allows anyone to change templates with query params or more likely load something without a real template because the url was typed incorrectly or correctly without the query parameter.
I can't make an api call from the templateUrl function because it's not injectable so I can't use the $http service. I've tried to use template provider but haven't made anything functional out of that yet. It does allow for an injectable function but that function must return an entire template instead of a url. If I can get a template url for it how can a load the template with that? I assume I'm not the first person to want dynamic templates (templates set in the database) from angular. What are my best options?
I have found a functional solution to my problem using ui-router, $stateParams, and $http. I'll be looking for a better architecture scheme as this necessitates 3 server requests every time a project is requested. One to get the template name and another to load the template file and another to load the project data. I suppose I only added one request to the norm. Anyways.. This solution is working for me but next I will be moving the logic to get template by the project name to an angular service to keep everything clean.
.state('projects/:project_url', {
url : '/projects/:project_url',
templateProvider : function ($stateParams, $http) {
return $http.get('/api/projects/' + $stateParams.project_url)
.then(function (data) {
// get template name
var templateName = data.data[0].template;
// return template by name
return $http.get('/pages/' + templateName + '.html')
.then(function (data) {
return data.data;
});
});
},
controller : 'projectCtrl'
});
http://dotjem.github.io/angular-routing/ supports your scenario with inject-able template functions. Note however that you must provide the raw template in the return statement, but that is easily done using the $template service...
It is very similar to UIRouter, so it should be a fairly easy transition if you find it worth it.
http://plnkr.co/edit/dkPIWMW236ixifETohNW?p=preview
If you take the latest stable release rather than the head you must add a "get" call to that service as: $template.get('template.html') rather than the newer: $template('template.html')

insert an iframe into page dynamically in AngularJS

I am trying to dynamically insert an iframe into a page with Angular 1.2. Here is the code:
html:
<div id="player_wrapper" ng-cloak>
<div ng-bind-html="player"></div>
</div>
js:
$http({method: 'GET', url: url}).
success(function(data, status) {
$scope.player = data.html;
}.......
So the data.html is a string that has a valid HTML starting with
<iframe ...>
The string contains also some div. So it could look like:
<iframe src='...' ...></iframe><div>some stuf</div>
I use in app.js 'ngSanitize'. What it shows is the div (after the iframe) but not the iframe itself.
If I use jQuery, basically a
$(#'player_wrapper').html(data.html)
works fine... but trying to make it proper angularJS.
Any idea on why only the divs after the iframe are being displayed?
Many thanks all
ngBindHtml will pass your HTML through $sce.getTrustedHtml before displaying it. I suspect this is what would be removing your iframe.
According to the docs you can use $sce.trustAsHtml to avoid this check so long as you fully trust any HTML coming from this source - an iframe from an untrusted source could likely do a number on nasty things to visitors to your page.
$http({method: 'GET', url: url}).
success(function(data, status) {
$scope.player = $sce.trustAsHtml(data.html);
}.......
Be careful! :)
You need to use the $sce service as desribed in the documentation of ng-bind-html:
$scope.player = $sce.trustAsHtml('your html goes here');
See this plunk for an example:
After much trouble I managed to get a nice setup going where I can dynamically load iframes into my page and pass information through to it.
I made this a github project. It uses a single directive for passing raw input element information, and also uses ngSanatize for the $sce.trustAsResourceUrl function.
Here is the live demo

Preload AngularJS partials used in routes?

Question: What is the best way and the best time to pre-load .ng files that are used in routing templates?
In researching this thus far, I've found the following answers:
Use Angular's script directive.
Problem: My content cannot be loaded as a literal string but needs to be fetched from the server. In other words, I have an .ng file as my partial so I cannot do
my content must remain in a .ng file on the server and be fetched
Use $templateCache.put to put a template literal in the cache. Same problem as above.
Use $http to load the .ng file. This works in that it is not a string literal but I am struggling to find the best time to perform this so that it is not blocking (realize its async but still)
To save you from suggesting resources I've already seen, I've read the following:
Is there a way to make AngularJS load partials in the beginning and not at when needed?
https://groups.google.com/forum/#!topic/angular/6aW6gWlsCjU
https://groups.google.com/forum/#!topic/angular/okG3LFcLkd0
https://medium.com/p/f8ae57e2cec3
http://comments.gmane.org/gmane.comp.lang.javascript.angularjs/15975
Maybe use a combination of 2 and 3.
Like you said, $http is async, so why not just put each partial into the templateCache after the app has loaded.
For example:
var myApp = angular.module('myApp', []);
myApp.run(function($http, $templateCache) {
var templates = ['template1.ng', 'template2.ng'];
angular.forEach(templates, function(templateUrl) {
$http({method: 'GET', url: templateUrl}).success(function(data) {
$templateCache.put(templateUrl, data);
});
});
});
I've never had the need for this and definitely haven't tested it, but the idea is there.

Resources