I am looking for how to add html which is a return of the web service, in angular. The problem is that the angular directives do not rendered. here is my source code
//tohtml.directive.ts
import { Directive, ElementRef, OnInit } from '#angular/core';
#Directive({
selector: '[appToHtml]'
})
export class ToHtmlDirective {
constructor( private el: ElementRef) {}
tohtml() {
//it is assumed that this is the return of the webservice
this.el.nativeElement.innerHTML = '<a
[routerLink]="/link/to/page">helpful!
</a>';
}
}
Code for component.html
<div id="wrapper">
<h1 appToHtml>
Hello World!
</h1>
</div>
the code works, but the rendering of the [routerLink] does not work, pleaseee hellppp !!!
By setting innerHTML prop in your directive you only set DOM and attributes. But this content need to be compile by angular to allow angular-like behavior (binding directives, instanciating components etc..) .
Angular dont have compiler ready to use like angularJS ( which has $compile ). You need to use 3rd party libraries like
https://www.npmjs.com/package/p3x-angular-compile
or
https://www.npmjs.com/package/ngx-dynamic-template
Those lib comes with handy examples. You should easily understand how to use them.
Be aware that you cant use AOT with such a rendering system.
Edition for ngx-dynamic-template usage :
if your dynamic templates need some directive of component, you have to configure ngx-dynamic-template to import the corresponding modules.
You can create a dynamic module like that in your case
#NgModule({
imports: [
RouterModule
],
exports: [
RouterModule
]
})
export class DynamicModule {}
and then when importing ngx in your appModule or SharedModule
#NgModule({
imports: [
...
NgxDynamicTemplateModule.forRoot({extraModules: [DynamicModule]})
...
],
Then you will be able to use routerLink without problem (i just tested)
in cmpt :
htmlTemplate = `<a [routerLink]="['dress-options']">link to user component</a>`;
in template :
<div dynamic-template [template]="htmlTemplate"></div>
With the latest angular version for me only this module works fine: https://www.npmjs.com/package/ngx-dynamic-template
v2.1.24 for angular4, v.2.3.0 is for angular5
Related
I want to "insert" task.component's view into my main app.component.html (root template) as follows:
(app.module.ts)
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { TaskComponent } from './task/task.component';
#NgModule({
declarations: [
AppComponent,
TaskComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
(app.component.ts)
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'planner';
}
(task.component.ts)
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-task',
templateUrl: './task.component.html',
styleUrls: ['./task.component.css']
})
export class TaskComponent implements OnInit {
constructor() { }
ngOnInit() {
console.log("Task comonent initialized!");
}
}
(app.component.html)
<!--The content below is only a placeholder and can be replaced.-->
<app-task></app-task>
<div style="text-align:center">
<h1>
Welcome to {{ title + 1 }}!
</h1>
<img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
</div>
<h2>Here are some links to help you start: </h2>
<ul>
<li>
<h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2>
</li>
<li>
<h2><a target="_blank" rel="noopener" href="https://github.com/angular/angular-cli/wiki">CLI Documentation</a></h2>
</li>
<li>
<h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2>
</li>
</ul>
So despite the fact that I have linked the task.component to the module I do not have access to its selector. Did I forget some import/export statements. Is that in fact a misunderstanding of angular's architecture/principle of structure?
The file task.component.html only consists of
<p>
task works!
</p>
Edit:
I also received the following error from the client's console:
[
What exactly shows in the place of the selector <app-task></app-task> that you added in app.component.html ?? What error in the console. This selector should work and be rendered to TaskComponent html view !!!!
To add a New Component to the Module that you're working on (which in your case is the AppModule), you first create a component(just use AngularCLI to do this by running the command ng g c task), and Angular CLI automatically adds it to your AppModule's declarations array. Then you can simply add the selector tag to your app.component.html to load that up
Just add <app-task></app-task> to your app.component.html
UPDATE
In some cases, even when you do everything properly, Angular doesn't recognise the Component that was added recently. Try breaking your local service by Ctrl + C on Windows or Cmd + C on Mac. And then run ng serve to serve up the App again. This generally happens when a Component is Added while the Server is running.
Here's a Sample StackBlitz for your ref just to cross check if you missed something.
I don't know what did you mean for linking components?
Following the structure that you shared it's working if you want see something, you must create the task-component.html because doesn't exist.
And the idea a component is that each component must has its logical indipendent to work.
And ways to share resources is using EventEmitters or binding properties.
This is the sceenshot that I saw and I can see the component created.
In fact restarting the server with ng serve did not solve the problem and therefore was not responsible for the missing interpolation of the component's template.
Rebuilding the app was the only (and ugliest) option for me which caused additionally work of course.
Delete all files of your project (all files in the layer in which amongst others node_modules is placed)
Setting up the project with ng new (...)
Building clean components with terminal commands (ng g c (...) / ng generate component (...))
Try re-running ng serve after stopping it. Hope you added component using Angular-Cli command -
ng generate component task
In the below code from ../src/app/app.module.ts,
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
Component consists:
view(../src/app/app.component.html)
logic(../src/app/app.component.ts)
style(../src/app/app.component.css)
Angular application is a tree of components. Good components have high cohesion, i.e. each component contains only elements with related functionality. They are also well encapsulated and loosely coupled.
How modules are different from components?
A component is just a class with the #Component() annotation. Note that .html and .css files might be referenced by the component, certainly not mandatory. The component template might very well be 'inlined' directly in the component configuration, or there simply might not be any html template at all for a given component.
A module is a structural element of an Angular application (and maybe other classes and interfaces). It is also "just a class" with the #NgModule() annotation.
It acts as a logical 'container' for your components, directives, services, pipes, etc... to help you structure your overall source code better.
You can have a look at this existing question : What's the difference between an Angular component and module
A module is something that has components. It wraps them up so you can import and manage them.
Notice when you make a component you can put anything that's decorated as #Injectable in your constructor:
#Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
constructor(private myService: MyService) { }
ngOnInit() {
}
}
And magically you will have a myService to use. This is dependency injection, which is built into Angular - but it's managed on a Module level. In your module you import what other modules you want to be able to use:
imports: [
BrowserModule,
FormsModule
],
define what your module includes:
declarations: [
AppComponent,
HeroesComponent,
MyService
],
export any components (so other modules can import them)
exports: [
HeroesComponent
],
They help organize an application into blocks of functionality. Components are things that tell angular how to render something. Modules compose Components, Pipes, Services etc into 'blocks' that can be compiled by angular or imported and used by others.
Edit to address comment
Taking your specific question about HttpClient. The HttpClient is the service you are using to perform the actions. The HttpClientModule is the module you import into your module, so you can use the service it contains.
You import the module:
#NgModule({
imports: [
BrowserModule,
// Include it under 'imports' in your application module
// after BrowserModule.
HttpClientModule,
],
})
And use the service:
#Component(...)
export class MyComponent implements OnInit {
// Inject HttpClient into your component or service.
constructor(private http: HttpClient) {}
...
}
The HttpClientModule contains within it all you need for the HttpClient to work, and packages it up so you can use it in your own projects.
This particular module only wraps up that one service, but the module could contain a bunch of related services, components, pipes or directives. For example, the RouterModule allows you to use the RouterOutlet and RouterLink directives.
Module in angular is set of Components, Services, Filters, or some another smaller modules too, or we can say where you import all these in order to use later in the app for future use. in a single app there can be one or more than one module may exist.
Whereas, A component controls a patch of screen called a view.
You define a component's application logic—what it does to support the view—inside a class. The class interacts with the view through an API of properties and methods.
Refer this guide for more details:
https://angular.io/guide/architecture
I'm thinking of separating our MVC-based website's front-end into few components and I was thinking about using Angular for that purpose (e.g. creating cart application that I can include to my view afterwards).
Problem is that I need to pass few variables into that application and I'm wondering how to do that safely and professionally. I was thinking about something like:
I'm going to ng build --prod --aot
I inject all my scripts to my view
I inject variables passed to view to my app
... and "code" representation for my thoughts:
Controller:
public function viewAction()
{
$this->view->addCss('angular/app/styles.css'); // adds styles for cart app
$this->view->addJS('angular/app/scripts.js'); // adds scripts for cart app
$this->view->setJSVariable('idCustomer', 555); // sets global var idCustomer
}
View:
<!-- bunch of HTML for view ... -->
<script>
// CartApp would be an angular app.
CartApp.use([
idCustomer
]);
</script>
So my question is... would it be possible (and would it be a good solution) to get the CartApp as an object and then make some function (like use in above example) that would set/pass the data? (let's say to some globally provided service/component or anything else). Or is there any other way to do this? Like taking the variables from inside the application from the window object? (as they're going to be bound to the window anyways). Thank you.
So I was going to suggest using input bindings... I've done that before in AngularJS but was surprised to find that using input bindings on the root component isn't supported yet. You can have fun reading this giant issue: https://github.com/angular/angular/issues/1858
The best post I saw there was Rob Wormald's which had a couple of suggestions:
to the initial question, if you really want to grab data from the
root, that's possible via
https://plnkr.co/edit/nOQuXE8hMkhakDNCNR9u?p=preview - note that it's not an input (because there's no angular context outside of it to do the input...) - its a simple string attribute
which you'd need to parse yourself.
ideally though, you'd do as
#robtown suggested and actually pass the data in javascript, rather
than passing it as a DOM string and retrieving / parsing it yourself
(which has never really been a supported case in angular, despite the
explicit-warned-against usage of ng-init in angular1 to accomplish
this) - see https://plnkr.co/edit/PoSd07IBvYm1EzeA2yJR?p=preview for a
simple, testable example of how to do this.
So the 2 good options I saw were:
Add normal HTML attributes to the root component:
<app-root appData='important stuff'></app-root>
and use ElementRef to fetch them:
#Component({
selector: 'app-root'
})
export class AppComponent {
constructor(el: ElementRef) {
console.log(el.nativeElement.getAttribute('appData'));
}
}
Would probably work best if you are just dealing with strings or config flags. If you are passing JSON, you will need to manually parse it.
Have the server render the data as JavaScript and import it in your app:
Have the server render something like this to a script tag or JS file that is loaded before Angular is bootstrapped:
window.APP_DATA = { ids: [1, 2, 3] }
Tell your NgModule about it using a provider:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
#NgModule({
providers: [{ provide: 'AppData', useValue: (<any> window).APP_DATA }],
bootstrap: [AppComponent]
})
export class AppModule { }
And then use it as a normal Angular service:
import {Component, Inject} from '#angular/core';
#Component({
selector: 'app-root'
})
export class AppComponent {
constructor(#Inject('AppData') appData) {
console.log(appData.ids);
}
}
I'm working on an Angular4 project and I have created a filter on my app.component.ts which I'm currently using on my app.component.html.
<button (click)="filterBy('cars')">Cars</button>
This works fine in this file by I want to use this same filter on my nav.component.html but I'd like to avoid recreating the filter code again on the nav.component.ts.
Is there a way of using this filter on my nav.component.html from app.component.ts ?
Migrate your created filter code in some new .ts file. Import this file in your app.component and other components by using import {ClassName} from file.ts syntax and then easily implement it in your component html code
You can create service, for example "filter.service.ts". Good thing in service is - it will create only one instance. So you use less memory, and app is faster.
Then - you can include it to the parent module:
import { FilterService } from "some/filter.service.ts";
#NgModule({
declarations: [ AppComponent, NavComponent],
providers: [ FilterService ]
})
export class MyModule { }
And use in your components like this:
import { FilterService } from "some/filter.service.ts";
constructor(filter: FilterService) {
this.filter = filter;
}
And then your html:
<button (click)="filter.filterBy('cars')">Cars</button>
#Injectable()
export class Service{
//create all the logic here for all the things you want to be shared across compponents
}
call this in the component you want to use like
import {Service} from "../shared/service";
#Component({
selector: 'app-angular4'
})
export class Angular4Component implements OnInit {
constructor(private service:Service) {
// resuse all the methods
}
In Angular, how would I compile a content sent through an API, similar to what $compile does in Angular 1.x, so I can get any possible routerLinks (or ngFor, ngIf, etc) working properly?
In other words, suppose that I get a content from an API which contains links based on routerLink. How can I compile that content so when I insert it into the website it will have the links functioning properly?
Example:
{
"title": "My post",
"content": "My link: <a [routerLink]=\"['about','123']\"">About</a>"
}
Ideally you would always have your return be split into elements that can be individual components, but in the real world this is probably not always possible.
I had a similar issue where I wanted my api response html to be compiled, rendered, interpolated etc. The only solution I have found uses compileModuleAndAllComponentsSync to compile a new module and component on the fly for a sort of dynamic component.
It goes like :
// First you need few modules loaded like Compiler
import { Component, NgModule, Compiler, ViewChild, ViewContainerRef} from '#angular/core';
// You need a place to load your dynamic content
// put <div #spot/> in the html you will be loading content into
#ViewChild('spot', {read: ViewContainerRef}) spot: ViewContainerRef;
// Remember to add them to the constructor
constructor(private compiler: Compiler , private route: ActivatedRoute
...
// On the get event from your API.
this.someservice.get(someid).subscribe(data => {
this.tmpComponent(this.data[0].someHtml);
...
// Then in your method, you create a new component
private tmpComponent(tpl: string) {
#Component({
selector: 'some-tpl',
template: tpl
})
class TmpComponent {
}
#NgModule({
imports: [
CommonModule
],
declarations: [
TmpComponent
],
exports: [
TmpComponent
]
})
class TmpModule {
}
var mod = this.compiler.compileModuleAndAllComponentsSync(TmpModule);
var factory = mod.componentFactories.find((c) => c.componentType === TmpComponent);
this.spot.createComponent(factory);
}