I am a beginner in angular 2 and I want to make my first app working. I am using TypeScript.
I have the app.component.ts in which I have made a directive to another compoent called todos.component but I am getting the following error at compile time:
[0] app/app.component.ts(7,3): error TS2345: Argument of type '{ moduleId: string; selector: string; directives: typeof TodosComponent[]; templateUrl: string; s ...' is not assignable to parameter of type 'Component'.
[0] Object literal may only specify known properties, and 'directives' does not exist in type 'Component'.
My code is like this:
index.html
<html>
<head>
<title>Angular 2 QuickStart</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<!-- 1. Load libraries -->
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<!-- 2. Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<!-- 3. Display the application -->
<body>
<app-root>Loading...</app-root>
</body>
</html>
app.component.ts
import { Component } from '#angular/core';
import {TodosComponent} from './todos/todos.component';
#Component({
moduleId : module.id,
selector: 'app-root',
directives: [TodosComponent],
templateUrl : 'app.component.html',
styleUrls : ['app.component.css']
})
export class AppComponent {
title: string = "Does it work?";
}
app.component.html:
<h1> Angular 2 application</h1>
{{title}}
<app-todos></app-todos>
todos.component.ts
import { Component, OnInit } from '#angular/core';
#Component({
moduleId : module.id,
selector: 'app-todos',
template: '<h2>Todo List</h2>'
})
export class TodosComponent {
title: string = "You have to do the following today:";
}
Without the directive, the app works fine.
Any help would be appreciated!
Thanks in advance!
In your app.component.ts you define directive: [TodosComponent].
The directive property has been removed in RC6 from the #Component() decorator.
The solution to this, is to:
create an NgModule and
declare the TodosComponent inside the declarations: [] array.
See here for an example of AppModule:
https://angular.io/docs/ts/latest/tutorial/toh-pt3.html
module.id was added in intially when angular2 was at beta version.Since with new version and angular cli support it is not required to add moduleId:module.id,you can remove from .ts files
Related
I am trying to move a web app to Angular2. I had successfully moved HTML & CSS to angular's component.html & component.css respectively. However, I am having trouble with .js files.
How do I incorporate .js file into component.ts?
.js file:
A = (function(w){
var init = function(){};
var scrollToElement = function(){};
}(window);
$(document).ready(function() {
A.init();
A.scrollToElement();
....
});
component.ts
import { Component, OnInit } from '#angular/core';
declare var $: any;
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor() { }
ngOnInit() {
$.getScript('assets/js/script.js');
}
}
Is this correct? What am I doing wrong?
It's better if you write js code in TypeScript in component.ts
and there is no need of jQuery's document.ready, window.load etc functions
because angular have its own life cycle hooks
see this --> See This
Using feedback by #SreedevR & #mlMughal, here's how i did it.
In index.html, I include the script file:
<!doctype html>
<html lang="en" class="no-js">
<head>
<base href="/">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<script src="assets/js/script.js"></script>
</head>
<body></body>
</html>
In component.ts:
export class HomeComponent implements OnInit {
A:any;
constructor() { }
ngOnInit() {}
ngAfterViewInit(){
A.init();
A.scrollToElement();
}
}
}
Please include the js in your main html file and you can call the fiction in the component.
Eg: If you script file is test.js please include that in the html file and call any function declared in it in the component like
f(){
new test();
}
Hope this is clear now
So i have an application where i need to be able to load different templates at runtime.
My standard template looks like this:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Template 1</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<app-root></app-root>
</body>
</html>
Now at one point i would like to change to the following template:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Template 2</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link type="text/css" rel="stylesheet" href="assets/reveal.js-3.6.0/css/reveal.css">
<link type="text/css" rel="stylesheet" href="assets/reveal.js-3.6.0/css/theme/black.css">
<link type="text/css" rel="stylesheet" href="assets/reveal.js-3.6.0/lib/css/zenburn.css">
</head>
<body>
<app-root></app-root>
<script type="application/javascript" src="assets/reveal.js-3.6.0/lib/js/classList.js"></script>
<script type="application/javascript" src="assets/reveal.js-3.6.0/lib/js/head.min.js"></script>
<script type="application/javascript" src="assets/reveal.js-3.6.0/js/reveal.js"></script>
</body>
</html>
My question is how can i do that? Either using components or modules?
I don't think it's a good practice to dynamically change the content of index.html, From what I can see, you only need to load few css and js files, when certain conditions are met.
Instead of touching the content of index file, how about handling what resources need to be loaded (and load them) inside a separate service while your application is being initialized?
It may look a little bit hacky, but it worked for me, at least for loading some additional css.
app.module.ts
export function ResourceProviderFactory( provider: ResourcesService ) {
return () => provider.loadResources();
}
#NgModule({
imports: [
...
],
declarations: [
...
],
providers: [
ResourcesService,
{
provide: APP_INITIALIZER,
useFactory: ResourceProviderFactory,
deps: [ ResourcesService ],
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule {}
resources.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable()
export class ResourcesService {
private _resources = {
typeA: [
'assets/reveal.js-3.6.0/css/reveal.css'
'assets/reveal.js-3.6.0/lib/js/classList.js'
]
}
constructor( private _http: HttpClient ) {
}
public loadResources(): Promise<boolean> {
let res;
if( condition_met ) {
for( let r of this._resources.typeA ) {
res = this._resources.typeA[r];
if( res.indexOf('css') >= 0 ) {
loadCSS( res );
}else if ( res.indexOf('js') >= 0 ) {
loadJS( res );
}
}
}
}
public loadCSS( resourcePath: string ) {
const link = document.createElement( 'link' );
link.type = 'text/css';
link.rel = 'stylesheet';
link.href = 'resourcePath;
document.getElementsByTagName( 'head' )[0].appendChild( link );
}
public loadJS( resourcePath: string ) {
const link = document.createElement( 'link' );
link.type = 'application/javascript';
link.href = resourcePath;
document.getElementsByTagName( 'head' )[0].appendChild( link );
}
}
You could divide your application in one main and multiple sub-layouts.
The application to land on the main layout-component and then load sub-layout on condition having its own styles (you can import additional CSS in sub-component's own css file)..
main-lauoyt.component.html: (The application lands here)
<router-outlet></router-outlet>
sub-layout-1.component.html (all layout type 1 components land here)
<router-outlet></router-outlet>
sub-layout-1.component.css
#import 'path to assets/reveal.js-3.6.0/css/reveal.css';
#import 'path to assets/reveal.js-3.6.0/css/theme/black.css';
#import 'path to assets/reveal.js-3.6.0/lib/css/zenburn.css';
(Do the above for type 2 layout component and import the other bunch of css files there)
Set your paths like this:
{path: 'type1', component: layoutType1Component,
children: ["all the child component paths of type-1 layout"],},
{path: 'type2', component: layoutType2Component,
children: ["all the child component paths of type-2 layout"],},
<ng-template [ngIf]="lessons" [ngIfElse]="loading">
<div class="lessons-list">
...
</div>
</ng-template>
<ng-template #loading>
<div>Loading...</div>`enter code here`
</ng-template>
In angular 2 how can I make the canonical tag dynamic per page.
This is my index page tag for it:
<link rel="canonical" href="https://mywebsite.co.uk" />
How can I make it dynamic e.g. if on blog page it should look like this at run time:
<link rel="canonical" href="https://mywebsite.co.uk/blog" />
I'm using angular version 4, webpack and typescript with ng2-metadata to change the title, description and keywords of all my urls.
I just need the canonical tag to change for the seo google bot.
I implemented a service that is called in the ngOnInit functions of my page components:
import { Inject, Injectable } from '#angular/core';
import { DOCUMENT } from '#angular/common';
#Injectable()
export class LinkService {
private link: HTMLLinkElement;
constructor(#Inject(DOCUMENT) private doc) { }
createLinkForCanonicalURL() {
if (this.link === undefined) {
this.link = this.doc.createElement('link');
this.link.setAttribute('rel', 'canonical');
this.doc.head.appendChild(this.link);
}
this.link.setAttribute('href', this.doc.URL.split('?')[0]);
}
}
Source: https://www.concretepage.com/angular/angular-title-service-and-canonical-url
I am unable to communicate between two component in Angular 2 using JS. This is link for tutorial.
I think I am missing something with directives.
I tried to change it with declarations as well
This is app.main.js
(function () {
var Component = ng.core.Component
var bootstrap = ng.platformBrowserDynamic.bootstrap
var RandomComponent = Component({
selector: 'random-component',
template: `
<h2> Hsdsdffdsdfi <h2>
`
}).Class({
constructor: function() {
//empty
}
});
var AppComponent = Component({
selector: 'main-app',
directives: [RandomComponent],
template: `
<h1> Hi {{username}}<h1>
<random-component></random-component>
`
}).Class({
constructor: function() {
//empty
this.username = "Username"
}
});
document.addEventListener('DOMContentLoaded', function(){
bootstrap(AppComponent);
});
})();
and this is index.html
<html>
<head>
<title>Angular 2 QuickStart JS</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<!-- 1. Load libraries -->
<!-- IE required polyfill -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/rxjs/bundles/Rx.umd.js"></script>
<script src="node_modules/#angular/core/bundles/core.umd.js"></script>
<script src="node_modules/#angular/common/bundles/common.umd.js"></script>
<script src="node_modules/#angular/compiler/bundles/compiler.umd.js"></script>
<script src="node_modules/#angular/platform-browser/bundles/platform-browser.umd.js"></script>
<script src="node_modules/#angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js"></script>
<!-- 2. Load our 'modules' -->
<script src='app/app.main.js'></script>
</head>
<!-- 3. Display the application -->
<body>
<main-app>Loading....</main-app>
</body>
</html>
I am currently using Angular 2 RC5, and do not wish to go to ts. I also could not find any documentation regarding JS as well. If anyone knows a good documentation link for 'JS' (not ts), please help with that as well.
NgModules
Angular2 RC5 introduced NgModules. According to the documentation,
Angular Modules help organize an application into cohesive blocks of functionality.
You need to define at least one module in your Angular application. You also should bootstrap that (root/main) module instead of a component (AppComponent in your case).
Another change is the way you declare your components and directives. Instead of using the directives property in every component, now you list them in the module using the declarations property.
Here's the working solution:
(function () {
var Component = ng.core.Component
var NgModule = ng.core.NgModule;
var BrowserModule = ng.platformBrowser.BrowserModule;
var bootstrap = ng.platformBrowserDynamic;
var AppComponent = Component({
selector: 'main-app',
template: `
<h1>Hi {{username}}</h1>
<random-component></random-component>
`
}).Class({
constructor: function() {
this.username = 'Username';
}
});
var RandomComponent = Component({
selector: 'random-component',
template: `
<h2>Random title<h2>
`
}).Class({
constructor: function() { }
});
AppModule = NgModule({
imports: [
BrowserModule
],
declarations: [
RandomComponent,
AppComponent
],
bootstrap: [
AppComponent
]})
.Class({
constructor: function() { }
});
document.addEventListener('DOMContentLoaded', function() {
bootstrap.platformBrowserDynamic()
.bootstrapModule(AppModule);
});
})();
Tutorials
Unfortunately, the Angular 2.0 docs about Javascript are definitely not as rich as the docs about Typescript. You can check the QuickStart Guide (there's and appendix regarding NgModule) or the corresponding Typescript chapter.
I am trying to setup my first angular2 application as an experiment and am using the latest beta release.
I am facing a weird issue where the variable i am using in my view is not being updated after setting a timeout.
#Component({
selector: "my-app",
bindings: []
})
#View({
templateUrl: "templates/main.component.html",
styleUrls: ['styles/out/components/main.component.css']
})
export class MainComponent {
public test2 = "initial text";
constructor() {
setTimeout(() => {
this.test2 = "updated text";
}, 500);
}
}
As you can see i have a variable named test2 and in the constructor i set a timeout of 500 ms where i am updating the value to "updated text".
Then in my view main.component.html i simply use:
{{ test2 }}
But the value will never be set to "updated text" and stays on "initial text" forever even though the update part is being hit. If i follow the angular2 tutorial they dont really give me an answer to this solution. Was wondering if anyone would have an idea of what i am missing here.
edit: my full code i am using including the bootstrap and html etc
<html>
<head>
<title>Angular 2</title>
<script src="/node_modules/systemjs/dist/system.src.js"></script>
<script src="/node_modules/reflect-metadata/reflect.js"></script>
<script src="/node_modules/angular2/bundles/angular2.dev.js"></script>
<script src="/node_modules/q/q.js"></script>
<script src="/node_modules/jquery/dist/jquery.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="/bower_components/breeze-client/breeze.debug.js"></script>
<script src="/bower_components/datajs/datajs.js"></script>
<script src="/bower_components/bootstrap-less/js/collapse.js"></script>
<script src="/bower_components/bootstrap-less/js/modal.js"></script>
<script src="/bower_components/signalr/jquery.signalR.js"></script>
<script src="http://localhost:64371/signalr/js"></script>
<link href="styles/out/main.css" type="text/css" rel="stylesheet" />
<script>
System.config({
map: {
rxjs: '/node_modules/rxjs' // added this map section
},
packages: {'scripts/out': {defaultExtension: 'js'}, 'rxjs': {defaultExtension: 'js'}}
});
System.import('scripts/out/main');
</script>
</head>
<body>
<my-app>loading...</my-app>
</body>
</html>
main.ts with the bootstrap:
import {Component} from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser'
import {COMMON_DIRECTIVES} from './constants';
import {MainComponent} from './components/main.component'
bootstrap(MainComponent);
main-component.html
{{ test2 }}
As Vlado said, it should work ;-)
I think that the angular2-polyfills.js library should be included into your page. I can't see it. This file is essentially a mashup of zone.js and reflect-metadata. Zones take part of the detection of updates.
You could have a look at this video where Bryan Ford explains what it is: https://www.youtube.com/watch?v=3IqtmUscE_U.
Hope it helps you,
Thierry
That should work. Do you have any other errors in console?
#Component({
selector: 'my-app',
template: `<h1>Hello {{title}}</h1>`
})
export class App {
public title: string = "World";
constructor() {
setTimeout(() => {
this.title = "Brave New World"
}, 1000);)
}
}
Look at this Plunker:
http://plnkr.co/edit/XaL4GoqFd9aisOYIhuXq?p=preview
I had a very similar problem to the OP where even in a basic Angular2 setup changes to bound properties would not be reflected by the view automatically. At this point in time we're using Angular2 2.0.0-rc.6.
There was no error message.
In the end I found the culprit to be a reference to es6-promise.js, which was 'required' by a third party component we use. Somehow this interfered with the core-js reference we are using which is suggested with rc6 in some of the Angular2 tutorials.
As soon as I got rid of the es6-promise.js reference, the view updated correctly after changing a property on my component (via Promise or timeout).
Hope this helps somebody some day.
In Angular2 (~2.1.2) another way to make it work is through the ChangeDetectorRef class. The original question code would look like this:
import {
ChangeDetectorRef
// ... other imports here
} from '#angular/core';
#Component({
selector: "my-app",
bindings: []
})
#View({
templateUrl: "templates/main.component.html",
styleUrls: ['styles/out/components/main.component.css']
})
export class MainComponent {
public test2 = "initial text";
constructor(private cd: ChangeDetectorRef) {
setTimeout(() => {
this.test2 = "updated text";
// as stated by the angular team: the following is required, otherwise the view will not be updated
this.cd.markForCheck();
}, 500);
}
}