angular dynamically generate html file - angularjs

I am trying to write a simple CMS system where the content of each page is stored in a database. When the user tries to access
/pages/abc.html
through angular routing and controller to retrieve the content of that page from the database and generate abc.html on the fly. I found one way is to add a function to templateUrl to return the page:
.when('/content/pages/:name*', {
templateUrl: function(parameters) {
return '/pages/' + parameters.name + '.html';
},
controller: 'ContentCtrl',
controllerAs: 'content'
})
However the issue is I need to have abc.html already exist and then in the controller to compile the DOM content and attach it. What I am trying to do is not to have the abc.html already exist, but generated on the fly. This way I can allow my user to add xyz content and when they try to access xyz.html it will be there, without having to create xyz.html template html upfront. Is there any method I can use to achieve this.

Is there any reason you need to generate the parameters.name html file? I would think you could define the template as then pass the html into the controller. If there is a lot of repeated logic, you could make a content component or directive.

What I did for this is write a custom directive. I pass the directive an array that contain objects that correspond to ui elements. The objects are defined in JS and all have a .html() function I wrote that generates some html based on the objects properties. Then to store/restore the structure you can just JSON.stringify the object to insert it in the DB and JSON.parse to get the object back... Only tricky part is you need to store the data type as a property of the object so you can pick the right type.
The directive itself just calls the html() function on each object and concatenates the output then sets the innerHTML of the element.

I realized I could just use the template property to insert any html I want.
.when('/content/pages/:name*', {
template: function(parameters) {
return 'hello' + parameters.name;
},
controller: 'ContentCtrl',
controllerAs: 'content'
})

What you can do it pass template name as a parameter to the controller:
.when('/content/pages/:name*', {
templateUrl: function(parameters) {
return '/pages/:templateName';
},
controller: 'ContentCtrl',
controllerAs: 'content'
})
And in the controller, create the required HTML (if not existing) and then in template include the HTML using ng-include:
<div ng-include="template.url" ng-if="template.url"></div>

Related

Automatically instantiate AngularJS controller nested in templateUrl

I'm just learning Angular and have a very basic app set up. When rendering some data via the templateUrl property of a route, what would be the best way to include a sub-controller in the returned template? For example, including a "createOrEditItem" template at the bottom of a "viewItem" template so that the "createOrEditItem" can be reused on its own later?
I've tried putting a div in the template with its ng-controller attribute set to a controller name that I've defined at the app level, but it's not being activated. Should this be done with a directive instead to make it instantiate when the master controller has its contents set, or am I missing something more fundamental?
yes, as mentioned in the later part of the question, you should be using a directive. Or, if using AngularJS >= v1.5, component should be the choice because they are pluggable and works well with nesting too.
Note that for the route also, you can directly use a component like this:
var myMod = angular.module('myMod', ['ngRoute']);
myMod.component('home', {
template: '<h1>Home</h1><p>Hello, {{ $ctrl.user.name }} !</p>',
// ^^^^ other components can be used here
controller: function() {
this.user = {name: 'world'};
}
});
myMod.config(function($routeProvider) {
$routeProvider.when('/', {
template: '<home></home>'
});
});
Now, as the comment suggests, you can freely use other components in the template of home component.
Hope this helps a bit!
A directive can be used.
Another option is to use a seperate view/route. So when you add a ui-view tag, you could define your view and route.
This is explained here:
https://scotch.io/tutorials/angular-routing-using-ui-router

angular ui-route state template with custom html tag

$stateProvider.state('abc', {
url: '/:id',
modal: true,
template: '<abc></abc>'
})
can I have custom html tag in template property?, e.g. 'abc', I was looking at someone else code but I don't understand how this works, I do have abc.html processed by gulp templatecache stuff. and it is loaded in a modal dialog correctly.
the file is at 'src/app/components/abc/abc.html', how come the template 'abc' knows which html to load? I suppose there must be a definition for 'abc' directive somewhere? but I can't find it.
I finally figured how it works, turns out the custom html tag is defined by a 'component' and there is some naming convention making this work.
http://blog.grossman.io/angular-1-component-based-architecture-2/
https://docs.angularjs.org/guide/component-router
Can I have custom html tag in template property
Yes, of course. Templates can use custom directives no matter how they are defined.
There should be an 'abc' directive somewhere in your module code or one of its dependencies.
See this SO question to be able to list the registered directives of your module and submodules in the console.
Yes, you can use custom html. UI Router provides you two choices, either you give the template or the templateUrl, which for the first one you have to write your html in a string literal, and latter you can set a html file location.
using template with string literal:
$stateProvider.state('abc', {
url: '/:id',
modal: true,
template: '<abc></abc>' // this is correct!
})
using templateUrl with html files.
$stateProvider.state('abc', {
url: '/:id',
modal: true,
templateUrl: '/path/to/abc.html' // if you have a file named `abc.html` in directory `path/to`, the template will be loaded
})

Find element in angular template from controller

I'm working with a directive.
Here is simple format of my directive:
angular.module('app',[]).directive('companylookup', CompanyLookupDirective);
function CompanyLookupDirective() {
return {
templateUrl: '<input id="foo"/>',
controller: 'CompanyLookupController',
controllerAs: 'vm'
}
}
I want to find input element with jquery in my controller (CompanyLookupController.js) like this:
var foo = $('#foo');
// decorate foo element using igniteui lib
$('#foo').igCombo({ datasource: ...});
But $('#foo') always return null. I can try to delay finding element with $timeout service to wait until element exist. But I don't want to do this so much times in my app in concern of performance.
Is there any way we can reference template elements in angularjs from a controller?
in template URL use escape character before quotes ,
templateUrl: '<input id=\"foo\"></input>'
Also i agree with #Robert Goldwein and if you absolutely have to, use link to manipulate DOM
EDIT : Help on link and compile functions.

How to insert template in html using angular?

Scenario:-
I have html page rendering as angular template/view. Now there are big number of such template.
Now these templates has div in header part that is fixed through out the templates, now is there some-way that we can define one sub-template at one place and just insert that sub-template in all pages.
So that if there are any modification to be made, I will make in sub-template and that will be reflected in all the page.
Its like UserControls or Partials that we have in ASP.Net.
I am using AgularJS
Agreed that there are ui-routing for nested hosting but currently I am not looking for that.
Try
<div ng-include="path/to/template"></div>
you can create a seperate html file as template for header if it includes complex or considerable amount of elements. create a directive for this template and use it as an attribute/customTag or include it in your html using ng-include.
app.directive('header',function(){
return {
restrict: 'E', //'E': element /'A': attribute
templateUrl : 'templates/header.html'
}
});
use as attribute
<div header></div> // as Attribute
<header></header> // as element
if your header involves lot of functioning on it then you can also create a separate controller (which will act as a child controller) and add the controller to the above tags. such as
<header ng-controller="headerController"></header>
You probably want to use a directive template. This is a very simple directive with only the template information.
Eg:
<top-header></top-header>
module.directive('topHeader', function() {
return {
templateUrl: 'path',
// append
replace: true,
// attribute restriction
restrict: 'E'
}
});

How to load language-specific templates in AngularJS?

I have a route defined as
$routeProvider.when('/:culture/:gameKey/:gameId/closed', { templateUrl: '/templates/tradingclosed', controller: TradingClosedCtrl });
I would like angular to include the "culture" parameter when requesting the template somehow, so I can serve a translated template.
Is this possible?
If I'm reading this correctly you'd like to somehow use the culture parameter from the url route to determine which location to retrieve your template.
There may be a better way but this post describes retrieving the $routeParams inside a centralized controller with ng-include to dynamically load a view.
Something similar to this:
angular.module('myApp', []).
config(function ($routeProvider) {
$routeProvider.when('/:culture/:gameKey/:gameId/closed', {
templateUrl: '/templates/nav/urlRouter.html',
controller: 'RouteController'
});
});
function RouteController($scope, $routeParams) {
$scope.templateUrl = 'templates/tradingclosed/' + $routeParams.culture + '_template.html';
}
With this as your urlRouter.html:
<div ng-include src="templateUrl"></div>
You can define the controller you want to load in your views using ng-controller and access the $routeParams for the additional route parameters:
<div ng-controller="TradingClosedCtrl">
</div>
I've posted similar question with working Plnkr example of solution like #Gloopy suggested.
The reason why you can't implement that without ng-include is that routing is done in 'configuration' block, where you can't inject any values (you can read about these blocks in Modules documentation, section Module Loading & Dependencies
If you want not to introduce new scope, you can replace ng-include with my stripped version of ng-include directive, that do absolutely same that ng-include does, but do not create new scope: source of rawInclude directive
Hope that solution will satisfy your use case.

Resources