Angular.js load, process and display dynamic template obtained via REST $resource - javascript

I have an Angular app that needs to support customizable reporting. My intention is to allow the user to select one of many reports available and have a back end REST api provide the template and the data as JSON (end user can customize the template).
The app would then insert the template somehow into a "reporting" view page then put the data in the scope and Angular should compile and display the report / template.
I've looked into ng-include however that seems to support only an URL or path to a document, however I have the template text already via the REST service and I cannot use static urls or file paths, this needs to be via REST api, if ng-include accepted the template text directly that might work but it doesn't.
I've tried writing a directive, trying to call a method on the page (getTemplate()) that would load the template already fetched from the scope however my directive doesn't have access to the scope apparently.
What tactic should I use to accomplish this? A directive seems best but I'm obviously doing it wrong and completely lost in the docs and my many attempts trying to accomplish this.

You could compile the dynamic template to an element on the DOM in a controller and then in the controller have something like this:
var el = angular.element('#myselector');
el.html(mydynamichtmlfromresource);
$compile(el.contents())($scope);
I would setup your route with template with single DIV container (you could pull all the static container template in a single JavaScript file using HTMLToJS online tool or grunt task):
<section class="view">
<div id="myselector"></div>
</section>

I've tried writing a directive, trying to call a method on the page
(getTemplate()) that would load the template already fetched from the
scope however my directive doesn't have access to the scope
apparently.
Yes you are right, but there is a way to pass data from scope to directive. lets say you want to pass a var "x" from scope to directive
use this
<directive directiveVar='x'/>
inside directive, you need to use isolated scope
"scope": {
"directiveVar": "="
},
this variable will be available only in controller and postlink function, so your directive template needs to be like this
<ng-bind-html="directiveVar"/>
inside the postlink you may need to use this code snippet
$scope.directiveVar =$sce.trustAsHtml($scope.directiveVar)
References
http://docs.angularjs.org/api/ng.directive:ngBindHtml
http://docs.angularjs.org/api/ng.$compile

Related

Vue.js print raw html and call component methods

I am dynamically loading the html content from an ajax request. This html has some buttons like
<button #click="someComponentMethod">Add</button>
As you can see I am trying to call components methods. But Its not working.
I think instead of #click html's default attribute "onclick" should work. But this will only recognize the function that are defined in global scope. Can someone guide me how I can call component's function from core javascript i.e using "onclick".
Update
Ok! I got it that v-html will not compile that html. But can you guys tell me how can I call component method from javascript (i.e outside of component scope). In this way I will be able to use onclick="JAVASCRIPT_CODE_TO_EXECUTE_METHOD".
That content will not be compiled as mentioned in official docs :
The contents of the span will be replaced with the value of the rawHtml property, interpreted as plain HTML - data bindings are ignored. Note that you cannot use v-html to compose template partials, because Vue is not a string-based templating engine. Instead, components are preferred as the fundamental unit for UI reuse and composition.
Instead of loading html I end up saving component in JSON format. This component has a template property that stores the html string. In this way I am able to store and load component to and from database and it works without any issue.

Controllers in AngularJS and templates

I'm fairly new to AngularJS and I want to have the best practices from start. I want to know where should I put which controller I'll be using for a specific template. For now I've used this two:
In the html of the template
<div ng-controller="ImageManagerController"> </div>
In my routes.js
.state('home',{
url : '/',
templateUrl : '/src/images/views/home.html',
controller : 'ImageManagerController'
})
Is one of them better than the other?
Thanks for your time!
When you do both you will create 2 instances of the controller, you don't want that
The biggest advantage of setting it in the routing config is that any related resolve will be made available for injection in the controller that is referenced.
Also when you have a lot of routes it is easy to look up which controller you would need to modify for any specific route when they are all listed in a config
Using ng-controller directive in HTML :
This scopes the controller to a specific element on the page/template. That can make the code easier to read when you need multiple controllers on a single page and it allows the controller to be more specifically scoped.
New $scope object will created on ng-controller.
visible with page source or inspect element.
Controller in Route :
Allows you to specify a single controller for a template. Since this is part of the routing it makes it easy to find the controller that goes with the page. I use this to store and load overall page logic rather than element specific logic.
New $scope object is created per route on the ng-view.
Not visible with page source or inspect element.
If you will use this <div ng-view ng-controller="ImageManagerController"> then you'd need to change that controller as the route changed. So basically the router does that for you, and uses the controller you specified when you defined your routes.
I hope these differences will help you in deciding which to use.

Proper way to include a js library file in a directive, avoiding relative path that may change

I have a project which is not using any method for including angular code other then loading them directly into our html page (and won't get permission to include any tool for awhile from my manager).
Currently if I want to use a provided javascript/angular/bootstrap element I would simply include it in my index.html, something like:
<script type="text/javascript" src="../lib/angular/angular-file.js"/>
I am now writing a directive. In the html template I want to use an already written third party angular directive to provide a tree view. I thus would want to include this script within my directives html template to insure it's loaded, rather then trusting this to the index.html has already loaded the script.
However, I don't want to use a relative path, or at least am afraid doing so will cause my directive to break later. the html template for my directive is buried under a tree structure, something like " portal/modules/simulation/templates/whatever" I don't want to have to place "../../../../../lib" in the template because it's ugly, but also because there is a chance that we may move the angular files around and I don't wan that to break my directive.
Is there a cleaner way of including the library without making a presumption about multuple layers of file structure, some way to work relative to the 'top layer' of my file structure etc?
is it considered clean for my directive to have it's own lib directory that contains the third party angular directive, rather then being part of shared lib directory? For that mater I believe that the third party tree view directive I'm using is dependent on other angular and jquery code, so I don't know if I may accidentally be dependent on something in the top level index.html file loading some angular/jquery code my directive uses without realizing it. Am I over worrying about making my directive stand alone when I shouldn't?
Generally I pack up templates using grunt and grunt-angular-templates. If you use something like this, you can reference your template as myModule/fileNameOfTemplate, and since the template is already in memory (using the $templateCache) you don't make any extra requests and the code doesn't care at all about the path to the actual file.
Without adding extra modules, build steps, etc...
foo.js
var fooModule = angular.module('foo', []);
fooModule.run(['$templateCache', function ($templateCache) {
$templateCache.put("foo/mytemplate.hmtl", "Really" +
"really" +
"long" +
"string");
}])
fooModule.directive('bar', function () {
return {
templateUrl: 'foo/mytemplate.html'
}
});
Now it doesn't matter where you store the module - you're just pulling the file out of the template cache.
Alternatively, templateUrl can accept a function - you could write a function to determine the path of the module or something.. but that's going to be super brittle.

AngularJS inside AJAX page

I have a shell file called ajaxshell.html. This has an AngularJS app that loads another page called entrypage.html and renders that as HTML using $sce.
In entrypage.html I would like to use Angular for validation purposes - checking that certain fields have been edited, for example. However, entrypage.html simply cannot seem to find Angular(tested by using a simple ng-repeat) no matter which of the 2 pages I include it in.
How can I access Angular from within entrypage.html?
I would have entrypage.html brought in as the template for a directive, rather than a welded-in piece of HTML. If you need the URL to be dynamic, you can assign a function to templateUrl when declaring a directive, and it can put together the URL on-the-fly for you. Angular will then consider the page to be a valid component of itself.

Adding controller in script tag when using angular's $compile

When $compile-ing an angular HTML template string I'm trying to put additional controllers and directives inside a <script> tag and use those in the HTML template.
This way I'm essentially trying to implement some sort of plug-in-mechanism, so that I can load external files that augment my app's functionality.
The <script> tag does actually get evaluated, but my problem is, that the HTML template compilation takes place before the evaluation of the JavaScript. So the compiler complains about missing controllers.
Example:
http://plnkr.co/edit/8oZYhRHAjP84ecnl6hG3?p=preview
This example throws an error: Error: Argument 'Controller' is not a function, got undefined
If you delete lines 15-18 (the HTML that references the created conroller) in app.js, you can see in the console that creating a controller this way does actually work.
I finally managed to do it based on the solution in Loading an AngularJS controller dynamically.
Thx #JoseM, #MaximShoustin and #JussiKosunen for your hints and help.
http://plnkr.co/edit/fzmEZlP6bGBJqTOkfApH?p=preview

Categories

Resources