Is it possible to do reusable snippets within AngularJS templates? - javascript

I'm finding myself repeating the same snippets of code again and again, is it possible to do something like this in AngularJS:
<div ng-snippet="mySnippet">
This is a snippet
</div>
<div ng-snippet="anotherSnippet">
Yet another snippet!!
</div>
<ng:include src="anotherSnippet">
<ng:include src="anotherSnippet">
<ng:include src="mySnippet">
and the output of the above would be:
Yet another snippet!!
Yet another snippet!!
This is a snippet
I'm not necessarily looking for this exact "ng:include" solution or pattern but something that would reduce the repetition in my templates.

<script type='text/ng-template' id="mySnippet">
This is a snippet
</script>
<script type='text/ng-template' id="anotherSnippet">
Yet another snippet!!
</script>
<ng-include src="'anotherSnippet'"></ng-include>
<ng-include src="'anotherSnippet'"></ng-include>
<ng-include src="'mySnippet'"></ng-include>
This should be what you want.
Docs for script and ng-include.

This sounds like you want to use directives. Here is a simple example: http://jsfiddle.net/gyF6V/1/

Related

How multiple ng-app worked in angular (Why such behaviour?)

I tried giving two ng-app in an application , when i gave two ng-app like
<body>
<div ng-app="A">
<div ng-controller="AC">
</div>
</div>
<div ng-app="B">
<div ng-controller="BC">
</div>
</div>
</body>
Then second ng-app does not work.
But when i change the scope of first ng-app="A" from div to body then both works fine like
<body ng-app="A">
<div>
<div ng-controller="AC">
</div>
</div>
<div ng-app="B">
<div ng-controller="BC">
</div>
</div>
</body>
Can anyone let me know why this behavior as i am quite new to angular.
I wanted to know why it worked as i didn't called angular.bootstrap on the second one.I tried searching but i didn't got how it is working when changing the scope of ng-app from div to body.
Find the fiddle for the same https://jsfiddle.net/maddyjolly2112/wyfd0djp/1/ and mind copying the js into the same .
Docs say: Don't use ngApp when instantiating multiple angular applications.
The reason you can't do this is laid out in the docs for the ngApp directive.
Only one AngularJS application can be auto-bootstrapped per HTML document. The first ngApp found in the document will be used to define the root element to auto-bootstrap as an application. To run multiple applications in an HTML document you must manually bootstrap them using angular.bootstrap instead. AngularJS applications cannot be nested within each other.
But Bootstraping multiple Angular apps is possible...
To bootstrap multiple Angular apps, you have to reference each, and they logically can't be nested, or sharing an element; they need to be separate from each other. Because of this, you cannot use the directive, ngApp:
<html>
<head></head>
<body>
<script src="angular.js"></script>
<div id="appElementA"></div>
<div id="appElementB"></div>
<script>
var app = angular.module('A', [])
.controller('AB', function($scope) {
$scope.greeting = 'Welcome!';
});
var appElementA = document.getElementById('divAppA');
angular.bootstrap(appElementA, ['A']);
var bApp = angular.module('B', [])
.controller('BB', function($scope) {
$scope.greeting = 'Welcome to B app!';
});
var appElementB = document.getElementById('divAppB');
angular.bootstrap(appElementB, ['B']);
</script>
</body>
</html>
The above code would be how you'd do it for your apps. You'd then have to be sure you're assigning the controllers to the right angular application (app vs bApp, in the above example.)
But don't nest them!
You claim it 'works' when you nest them, but you should be aware that it doesn't work, it just doesn't crash hard. Don't have multiple angular applications nested. You'll encounter weird issues, especially if you have multiple variables named the same bound to the $rootScope.
But you can nest them without ill effects, right?
If you're intent on having two Angular apps nested; it's possible but extremely version specific and liable to break in weird ways. This Stack Overflow answer talks about it.
From Angular's official docs :
Only one AngularJS application can be auto-bootstrapped per HTML document. The first ngApp found in the document will be used to define the root element to auto-bootstrap as an application. To run multiple applications in an HTML document you must manually bootstrap them using angular.bootstrap instead. AngularJS applications cannot be nested within each other.
Source : https://docs.angularjs.org/api/ng/directive/ngApp
If the question is : why the second example works and not the first, the answer is in the link above > Angular needs the first ngApp to be placed near the root element of the page (html or body).
As George mentioned, manual bootstrapping will work.
In html, use id instead of ng-app.
In script
var dvFirst = document.getElementById('dvFirst');
var dvSecond = document.getElementById('dvSecond');
angular.element(document).ready(function() {
angular.bootstrap(dvFirst, ['firstApp']);
angular.bootstrap(dvSecond, ['secondApp']);
});
Here is a working plunker
http://plnkr.co/edit/1SdZ4QpPfuHtdBjTKJIu?p=preview

How to replace body class in Angular [ BEST WAY ]

in my index.html I have my <header> then <body> with some subelements and <footer> elements.
Rest of the code is in template for each page like templates/home.html, templates/login.html
For one of this page I need to replace:
<body class="page-homepage" ng-app="historyApp" id="body">
to
<body class="page-subpage" ng-app="historyApp">
Is there some nice way how to do it?
I find some ways with jquery like (take it as example):
var el = document.querySelector('#body');
el.classList.remove('page-homepage');
el.classList.add('page-subpage');
but I believe that many of you already had to deal with this is kind of problem.
Can someone suggest me how to do this in angular?
In my opinion, the best way to do this is to add a variable to your $rootScope
$rootScope.isSub = false;
And use ngClass directive on your body element :
<body ng-class="{'page-subpage':isSub,'page-homepage':!isSub}" ng-app="historyApp">
And for each controller specify the $rootScope.isSub value.

manipulating content with ng-bind-html and default content

I'm trying to use angular to reload (or 'livechange') content - the content default structure isn't created by angular.
so i have the following
<div>Default Value</div>
and i want to be able to rebuild the content with angular (ng-bind-html is a great solution, but it cant use 'default' value).
Any help would be appreciated. thanks!
You can do that using ng-hide/ng-show directive please see here http://plnkr.co/edit/oHJMD6UU3xOOg5HZo3IC?p=preview
<body ng-controller="MainCtrl">
<textarea name="comment" ng-model="myHTML"></textarea>
<div ng-bind-html="myHTML" ng-show="myHTML"></div>
<div ng-hide="myHTML">Default Value</div>
</body>

In AngularJS, any inline javascript code that included in HTML templates doesn't work

In AngularJS, any inline javascript code that included in HTML templates doesn't work.
For Example:
main.html file:
<div ng-include="'/templates/script.html'"></div>
And script.html file:
<script type="text/javascript">
alert('yes');
</script>
When I open main page, I expect an alert message that say 'yes' but nothing happens. I think some security restrictions in the AngularJS is preventing inline scripts, but I couldn't find any workaround about that.
Note: I don't use jQuery or any other framework, only AngularJS 1.2.7.
jQlite does not support script tags. jQuery does, so the recommendation is to include jQuery if you need this functionality.
From Angular's Igor Minar in this discussion:
we looked into supporting script tags in jqlite, but what needs to be
done to get a cross-browser support involves a lot of black magic. For
this reason we decided that for now we are just going to recommend
that users use jquery along with angular in this particular case. It
doesn't make sense for us to rewrite one third of jquery to get this
working in jqlite.
Here's the related github issue jqLite should create elements in same way as jQuery where Igor sums up, before closing the issue, with this:
This is too much craziness for jqlite, so we are not going to do it.
Instead we are going to document that if you want have script elements
in ng:include or ng:view templates, you should use jquery.
demo plunker with jquery
Angular uses the $sanitize on ng-include directives which strips out scripts. A better approach for templates is to create a controller for that template.
It is better to use an individual controller for templates.
In template.html
<form role="form" ng-controller="LoginController">
<input type="text" placeholder="Email" ng-model="email">
<input type="password" placeholder="Password" ng-model="password">
<button class="btn btn-success" ng-click="login()">Sign in</button>
</form>
In the LoginController you can use whatever code you want
angular.module('myApp.controllers', []).
controller('LoginController', [function() {
alert('controller initialized');
}])
The event triggered when ng-include adds content is $includeContentLoaded. Your scripts should be included in this event:
For example (Plucker Demo):
function SettingsController($scope, $window) {
$scope.template={};
$scope.template.url = "demo.html";
$scope.$on('$includeContentLoaded', function(event){
$window.alert('content load');
});
}
Additionally you can set an init function using the onload attribute:
html
<div ng-include="template.url" onload="alertMe()" > </div>
</div>
Controller
$scope.alertMe=function(){
$window.alert('sending alert on load');
}
Include jQuery and change order of the angular.js and jquery.js. jQuery must be first, otherwise it does not work

Get onClick element to return to the main element?

I'm awful with javascript and I'm having a problem with this one.
I'm using this code
<script>
function changeNavigation(id){
document.getElementById('members')
.innerHTML=document.getElementById(id).innerHTML
}
</script>
and HTML
`<span onClick="changeNavigation('members')" >MEMBERS</span>
<span onClick="changeNavigation('help')" >HELP</span>`
<div id="members>...</div>
<div id="help" style="display: none;>...</div>
But I can't get <span onClick="changeNavigation('members')" >MEMBERS</span> to actually go to an element "members" without duplicating everything inside of it in another id.
Is there a way to do this?
This can be done using only standard javascript, but personally I'd recommend going ahead and getting used to using jQuery. Here's an example jsfiddle using jQuery: http://jsfiddle.net/JnvCR/2/
Don't forget to include jQuery in your website:
<script src="http://code.jquery.com/jquery.js"></script>
You need to correct your syntax errors. Use onclick instead of onClick (pedantic). Make sure you close your attributes properly, you are missing a few closing " marks.
updated html
<span onclick="changeNavigation('members')" >MEMBERS</span>
<span onclick="changeNavigation('help')" >HELP</span>`
<div id="members">...</div>
<div id="help" style="display: none;">...</div>
There is also an error with your logic as you are simply replacing the contents of div#members with itself.
Updated JS without syntax errors, but still with dodgy logic
function changeNavigation(id){
document.getElementById('members').innerHTML=document.getElementById(id).innerHTML;
}
Demo fiddle
http://jsfiddle.net/ADGCV/
As far as your actual question goes, can you explain what you would like to happen a bit better??
Here's a possible solution http://jsfiddle.net/ADGCV/1/

Categories