For every example I come across in Angular 2 the template lives in the component decorator.
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template: '<h1>Hello world</h1>'
})
export class AppComponent { }
Is this the correct convention? When templates become complex I would imagine this syntax becomes cumbersome.
I have tried using templateUrl instead of template. But as I understand it Angular will then load the template via ajax. (Slightly related, but since I've updated to 2.0.0-rc.3 templateUrl no longer seems to be working, but maybe I'm doing something wrong).
What is the best way to handle templates?
You can use templateUrl in rc3; see below the template code for a basic component:
import { Component, OnInit } from '#angular/core';
#Component({
moduleId: module.id,
selector: 'app-my-component',
templateUrl: 'my-component.component.html',
styleUrls: ['my-component.component.css']
})
export class MyComponentComponent implements OnInit {
constructor() {}
ngOnInit() {
}
}
templateUrl should be used as a normal practice to keep the component definition clean.
The official ng2 tutorial will help clarify some of the base-questions , it helped me : https://angular.io/docs/ts/latest/tutorial/
From the Angular2 style guide
| Do extract templates and styles into a separate file, when more than 3 lines.
The upcoming offline template compiler will inline templates linked by templateUrl. There are also Gulp tasks available to do this already.
The official style guide
https://angular.io/styleguide#!#05-04
may suggest you to isolate styles and templates into different files.
But at the same time if you are shipping a component the single component file will make it easy and independent. So it is about your requirement. If you want your component to be reused independently this approach where embedding the template file into the component would win. And in the end it's your choice.
Hope this help you. Thank you.
Template url should be used for writing html code because of two reasons:
1. Seperation of concerns : A convention used for project development.
2. Easy debugging: in various IDE's you can use html lint plugins so as to find issue in html.
If your html is of one or two line then you can use it inline.
Related
The problem is that I have lots of HTML templates that include < script > tags with AngularJS code in them. My current project is using Angular 8, and one critical part of it consists basically in usign all the AngularJS templates that I have inside this new project doing as little work as possible (due to the fact that in the future other users will have to be able to add new templates to the project).
I have to be able to add this HTML AngularJS templates to my current project. For that I am using ngUpgrade, but it has been quite misleading and I have not been able o achieve this.
Here is one of the templates, simplified as much as possible for this question:
HTML
<body>
<script>
angular.module('myApp', [])
.controller('myController', function ($scope, $timeout) {
$scope.local = 'es';
BigFunction($scope, $timeout);
});
var texts = {
title: {
en: 'A simple title',
};
// other constanst go here
function BigFunction(scope, timeout) {
scope.texts = texts;
scope.$watch('content', function(end, ini){
// some logic when 'content' changes
}, true);
// more logic
}
<script>
<div>
<!-- Lots of tags using ng-bind and other AngularJS tools -->
</div>
</body>
I have to integrate it touching it as little as possible. I don't know if I should separate the logic of the script from the HTML, or if I could import it as it is right now and work. Take into account that I have no previous experience working with AngularJS, I am an Angular 2+ developer.
If I have to separate the logic from the template, where do I put the angular.module? And the constants?
I would suggest you using Web Components
Basically you would have to wrap the AngularJS application as a Web Component and then import it to your Angular 8 app. You would end up with something like this
<my-angularjs-app></my-angularjs-app>
It could be imported in any component in your Angular 8 application.
There is no official solution on how to do it, but there are good examples there. I would suggest you following this one:
UPGRADING WITH WEB COMPONENTS: FROM ANGULARJS TO ANGULAR
Once you are there scroll down until you see
Exposing AngularJS Components As Custom Elements
After you manage to bundle up the AngularJS application as a web component, having the whole application in one script (main.js), you would have to copy it to your Angular 8 app.
In your Angular 8 app, create folder assets/web-components/my-angularjs-app
Copy the file you generated from AngularJS (main.js) to a folder you just created
Import the file in angular.json - Add this to scripts: assets/web-components/my-angularjs-app/main.js
Your AngularJS app is now imported but there is one more thing we have to do before you can use it in your components. You have to let Angular know that there will be some selectors which Angular might not be aware of. To do this, go to your app.module.ts and add schemas: [CUSTOM_ELEMENTS_SCHEMA]
You can now use your AngularJS app anywhere you prefer by using the selector you declared (This part is in the link I posted). <my-angularjs-app></my-angularjs-app>
I recommend the ng-book, it has a full chapter about hybrid apps. Note the UpgradeAdapter in the book is deprecated. But many concepts are still valid.
NgUpgrade is the official package to do what you want.
The first thing you must do is to put the script in a proper file. And not in the HTML. Then you can do serious coding.
You must follow the NgUpgrade doc to make the 2 apps run.
https://angular.io/guide/upgrade#bootstrapping-hybrid-applications
you need one bootstrap for AngularJS:
angular.bootstrap(document.body, ['heroApp'], { strictDi: true });
And one bootstrap for Angular 8:
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
platformBrowserDynamic().bootstrapModule(AppModule);
You will notice the NgModule has a reference line towards AngularJs.
The code they give is for JIT compilation.
A production build in AOT compilation will look like this:
import { enableProdMode } from '#angular/core';
import { platformBrowser } from '#angular/platform-browser';
const { AppModuleNgFactory } = require('../aot/src/app/AppModule.ngfactory');
enableProdMode();
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
--
You must know a directive in AngularJS corresponds to what is meant by component in Angular 8.
You have 2 options.
inject Angular 8 components in ANgular JS directives
inject Angular JS directives in ANgular 8 components.
I recommend to upgrade ANgularJs Components inside Angular 8 components. Like that in the future you converge towards moving to Angular 8 only.
It will require some work to copy each AngularJS component in an Angular 8 component.
To reduce work, run Angular JS as it is. And put Angular 8 directives outside of the templates of AngularJS.
<div id="angularjs-root"></div>
<div my-unaltereted-angular8-component></div>
It may be I am wrong and you cannot put them deparately. But it is worth a try.
Myself, I inject DOM elements dynamically from Angular8 to a JQuery application. But you cannot do that in AngularJS since it has lifecycle for all nodes. HOwever, with some carefulness, removing change detection rendering for the node, a huge tree of nodes from Angular 8 could be injected in the template of an ANgularJs template, and this wihtout downgrading.
This is what I use.
addComponentToElement({ component, element }: { component: any, element: any }) {
// Create a component reference from the component
const componentRef = this.componentFactoryResolver
.resolveComponentFactory(component)
.create(this.injector);
// Attach component to the appRef so that it's inside the ng component tree
this.appRef.attachView(componentRef.hostView);
// Get DOM element from component
const domElem = (componentRef.hostView as EmbeddedViewRef<any>)
.rootNodes[0] as HTMLElement;
// Append DOM element to the body
element.appendChild(domElem);
// detect changes
componentRef.changeDetectorRef.detectChanges();
}
The AppModule will need to add each component inside entryComponents:
entryComponents: [ InjectedCOmponent1m InjectedCOmponent2]
I am trying to interact with the HelpScout beacon via their API methods however struggling to interact with the DOM from the controller.
I have tried running functions such as
document.HS.beacon.ready(function() {
// Open the Beacon as soon as it's ready
this.open();
});
on various lifeCycle hooks such as ngAfterViewInit() however, I get a number of errors in the compiler for as HS is not a property on document.
There are numerous component based JS frameworks that must have a robust solution for interacting with libraries that are delivered via CDN? I would rather they packaged up the code and ran it as an npm / yarn package, however that is not the case.
Many thanks in advance.
EDIT: I note that they are simply injecting this code : https://djtflbt20bdde.cloudfront.net. I might just run this locally? Ideas?
I suppose you could init the Beacon object via script tag, that creates an instance of the Beacon object as a property of window. If you need to interact with this object inside an Angular component or service, you should declare it first (in my case, I needed to destroy the Object):
import { Component } from '#angular/core';
declare let Beacon: any ;
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
closeBeacon(){
Beacon('destroy');
}
}
I'm studying Angular 2 internal components and behaviors and I'm having some questions concerning the component tree management.
In a web app based on components, it's clear that we have a component tree. One component is composed of another one, from top to bottom, and it's really powerful.
But now, I m wondering how does angular 2 manages the representation of this component tree internally ?
What I mean there is that we never say in an angular component, what components will be inside of it, except in the template.
For example, I never say in my HomeComponent definition that it owns a PrestaCardComponent :
import { Component, OnInit, Inject } from '#angular/core';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
prestations: Array<any>;
featurettes: Array<any>;
constructor( #Inject('AppStore') private appStore: any) {
this.prestations = [];
this.featurettes = [];
}
ngOnInit() {
}
}
Except in my template :
<div *ngFor="let prestation of prestations" class="col-md-4 m-b">
<app-presta-card [title]="prestation.title" [content]="prestation.content" [image]="prestation.image"></app-presta-card>
</div>
What I understand it means
It means that Angular 2 is able to create the virtual component tree, by reading the different templates.
How can it be possible ? How does it work ?
Use Augury. you will get a clear insight.
NgModules are key to understanding how Angular deciphers the template when it parses it.
Look into the definition of these properties while decorating with #NgModule,
declarations : List of components, directives, and pipes that belong to this module.
imports : List of modules to import into this module. Everything from the imported modules is available to declarations of this module.
exports : List of components, directives, and pipes visible to modules that import this module.
using this knowledge Angular knows what selector means what, and using Reflection it gets Metadata for the component.
Of course there is more to it, but this may be a start.
Hope this helps!!
All the configuration of your components are rooted in an NgModule.
As Madhu Ranjan already mentioned in his answer there are the following 3 important parts in an NgModule, namely being:
declarations : List of components, directives, and pipes that belong to this module.
imports : List of modules to import into this module. Everything from the imported modules is available to declarations of this module.
exports : List of components, directives, and pipes visible to modules that import this module.
Actually there is even an FAQ for NgModule as it was a major change in the angular2 architecture since (I think) RC5.
Each and every component has to be part of an NgModule. It declares a part of your application which functionalities belong to each other. You can even nest NgModules inside each other with the imports part of it.
A positive part IMO is that you can organize your application very well with this structure as each angular module has its own routing configuration.
Furthermore you can limit accessability of services that should be used by declaring them inside e.g. a (sub-) module of another module just to name a few important features.
Check out the Angular2 Docs for more information about this and many more subjects. It is pretty detailed and IMO very easy to understand as the angular team took alot of effort of keeping it up to date and clean (when you don't mind searching a bit for the parts you need as the topic grouping is kinda crappy in the docs).
Currently I'm creating an app using Angular2 and Typescript.
I have different components for different sections in the application (Home, Profile page, ...) and a JS file for each section (home.js, profile.js).
I'm wondering if it's possible to include this file depends of the component is being loaded.
Other thing I have tried is to add the javascript file into the view of the component but looks like Angular is stripping it out.
Any advice or a better way to do this would be really appreciated.
Thank you
Finally I got it solved by myself.
What I've done is to implement AfterViewInit interface on my components, and load the script using jQuery.getScript method.
import {Component, AfterViewInit} from "#angular/core";
#Component({
moduleId: module.id,
selector: 'home',
templateUrl: '../views/home.html',
styleUrls: ['../../public/css/home.css']
})
export class HomeComponent implements AfterViewInit {
ngAfterViewInit(): void {
jQuery.getScript('public/js/home.js');
}
}
I hope this helps somebody with the same problem.
I want to create an application wide variable accessible between various angular2 components and imported modules.
I have looked at dependency injection in my app.module and thought maybe I could set a class with a property in that. However, with the new angular-RC5 release, this looks like an overcomplication for what I want to do.
Alternatively, I thought of using a #Inputs and #Outputs to cascade the data and subscribe to changes, however, that doesn't seem to be possible between modules.
I would be really grateful for a suggestion of the easiest way of doing this.
In terms of my particular application, I have a navbar component which I want to show on all routes except one. So I have that on my app.component template, with an *NgIf condition, which I then wanted to be able to change from various child components to display the navbar, without having to embed the navbar component in all of my child modules and components (which gets tricky with components being shared between modules. Some of my routes are imported in a module.
You can create a shared service.
something like that :
import { Injectable } from '#angular/core';
#Injectable()
export class GenericService {
data:any = {};
}
and then add it to your app.module.
after that you can inject it to your component and add datas on it who will be accessible from all your components.
This is usually done using a shared service.
For details see
https://angular.io/docs/ts/latest/cookbook/component-communication.html
https://angular.io/docs/ts/latest/cookbook/rc4-to-rc5.html
https://angular.io/docs/ts/latest/guide/ngmodule.html#!#q-why-it-is-bad