I was building an angular2 app in the expected language of typescript and I was having a ton of problem with 3rd-party typings and I was pulling my hair out with dealing with these typescript issue. So I boldly decided to instead give it a try in pure javascript. Crazy huh? Given the extreme lack of help to be found on the web.
But everything is working great with one exception, I can't get one way binding on a control to work. I am using an ES7 transpiler and so some of the annotations even work! So in the end it looks fairly similar to typescript (except for the typing of course).
app component html snippet
<results [results]="results"></results>
ResultsComponent
#Component({
selector: 'results',
templateUrl: '<div *ngFor="let result of results"><result [result]="result"></result></div>',
directives: [ResultComponent]
})
export class ResultsComponent {
#Input() results;
constructor(){};
}
In Typescript this was working fine. The results property in my ResultsComponent would be set to the value set in the app component. In the pure javascript version results is null. The code is reacting to the #Input decorator because if I take it away it complains about it being missing
EXCEPTION: Template parse errors:
Can't bind to 'results' since it isn't a known native property
but somehow the data is not coming through. Any ideas?
I found the answer in the inputs section of the Component decorator thanks to this link. I changed ...
#Component({
selector: 'results',
templateUrl: '<div *ngFor="let result of results"><result [result]="result"></result></div>',
directives: [ResultComponent]
})
export class ResultsComponent {
#Input() results;
constructor(){};
}
... to ...
#Component({
selector: 'results',
templateUrl: '<div *ngFor="let result of results"><result [result]="result"></result></div>',
directives: [ResultComponent],
inputs: ['results']
})
export class ResultsComponent {
constructor(){};
}
... and it works now!
Related
I have downloaded the Angular 2 quickstart and it worked fine after all of the setup. I setup an express server and connected to that and the app continued to work fine. I made one change to use component templateUrl rather than template property and it stopped working. I have created a Plunker, https://plnkr.co/edit/BSnwkRdwwHFZZs808v4m?p=preview
to demonstrate this. Below is the AppComponent code where I switch between properties.
import { Component } from '#angular/core';
#Component({
selector: 'pm-app',
templateUrl: './app.component.html'
//template: `<h1>Hello {{name}}</h1>`
})
export class AppComponent {
name: string;
constructor(){
this.name = 'FasterLearnerII';
console.log("App Component Called");
}}
The Plunk also works fine if the AppComponent uses the template property but stops working when I switch to the templateUrl. I could find no error message with plunker but when I run in the browser the message I get is:
EXCEPTION: Error in app.component.html:1:108 caused by: too much recursion core.umd.js:3064:13
ORIGINAL EXCEPTION: too much recursion core.umd.js:3066:17
ORIGINAL STACKTRACE: core.umd.js:3069:17
getErrorPropertiesForPrototype/<#http://localhost:3030/node_modules/zone.js/dist/zone.js:936:17
The problem is not browser specific as I have tried it in Firefox, Chrome and IE.
Appreciate any thoughts on why this is not working.
you have to put full path,
this gonna work:
#Component({
selector: 'pm-app',
templateUrl: 'app/app.component.html'
//template: `<h1>Hello {{name}}</h1>`
})
Since the app is big I will try to simplify below:
TagComponent :
#Component({
selector: "tag",
template: `<div *ngFor="let a of arr">{{a}}</div>`
})
export class TagComponent{
#Input() arr: string[];
add(){
this.arr.push("abc");
}
}
AppComponent :
#Component({
template: `<p><tag [arr]="data"></tag></p>`
})
export class AppComponent{
data: string[];
//some other code
}
So, when add() is called, only the first time the app scrolls to the top automatically and this only occurs in Outlook Desktop which is running a modified version of IE 11. Its a bit difficult to understand the problem and give a solution but any hints as to what might cause this will also count as an answer.
Quite new to Angular 2, and after looking around for few hours I'd like to have some help.
I have a JS file with some generic functions. For example:
$(document).ready(function(){
$('[data-toggle="tooltip"]').tooltip();
});
This file contains in fact way more code. As you can imagine, I'd like to enable tooltips of all components. I can't simply include this file in index.html because subcomponents aren't present (yet) when the file is loaded.
After some digging, afterViewInit() came up. This post suggests to copy/paste JS code into ngAfterViewInit(). That's the ugly way (in my opinion)...
So here I come with 2 related questions:
1# Is there a way to execute JS code when a child component is loaded? For example, something like:
// In app.component.ts
ngAfterChildComponentLoaded(){
// JS code here
}
This solution is quite interesting because I'm not forced to implement ngAfterViewInit() with the same content in all my components. But is it possible?
2# Is there a way to import JS code instrad of copy/paste it into ngAfterViewInit()? I don't want copy/paste 300 lines of JS code into 15 differents components (for obvious reasons).
Thanks a lot for your help!
See the following for how to get external js files for a particular component in angular 2/4:
import { Component, OnInit , AfterViewInit} from '#angular/core';
import { Router } from '#angular/router';
declare var $: any;
#Component({
moduleId: module.id,
selector: 'dashboard',
templateUrl: './dashboard.html',
styleUrls: ['./dashboard.css']
})
export class DashboardComponent implements OnInit,AfterViewInit {
constructor() {}
ngOnInit() {
}
ngAfterViewInit(){
$.getScript('assets/assets/build/js/custom.min.js');
}
}
Got a less-ugly solution, if someone has a better one I'll gladly accept his answer!
ngAfterViewInit(){
$.getScript('assets/js/myscript.js', function(){});
}
I'm reading lots of articles on this matter like this, and this and also this but each one of these articles starts from a situation in which the NG1 service is a class and can be exported.
I'm in a very different situation, i often have multiple services in the same file and they are defined in a very old style manner like
angular.module('App.services').factory('SessionService',
function() {
var defer = $q.defer();
[...]
}
);
No class, no export.
And this stuff is directly linked in the page with an old fashioned <script src="...">
At the same time i'm trying to create new directives in Angular2 and these directives need those old fashioned services.
I get i should be able to write something like this
import {Injector,Component, Directive, ElementRef, Input, View} from 'angular2/core';
var injector = Injector.resolveAndCreate([
SessionService
]);
var SessionService = injector.get(SessionService);
#Component({
selector: 'nav-bar'
})
#View({
templateUrl: '/app/components/navbar/navBar.html'
})
export class navBar {
constructor() {
}
}
but of course SessionService object is not found.
How can i get out of this mess?
[Additional Info]
Using babel as transpiler
angular2-annotations plugin added
A great article to understand the difference between Annotations and Decorators in angular2: http://blog.thoughtram.io/angular/2015/05/03/the-difference-between-annotations-and-decorators.html
You simply need to leverage #Inject:
#Component({
selector: 'nav-bar'
templateUrl: '/app/components/navbar/navBar.html'
})
export class navBar {
constructor(private #Inject('SessionService') sessionService) {
}
}
See this plunkr for more details: http://plnkr.co/edit/U6ygjUUQ04mTGAAaC1pZ?p=preview
You can notice that with factory you can't use classes. It's only possible with services...
If you use ES6 only, you could try this:
#Component({
selector: 'nav-bar'
templateUrl: '/app/components/navbar/navBar.html'
})
export class navBar {
constructor(sessionService) {
}
static get parameters() {
return [[ new Inject('...'), new Inject('...') ]];
}
}
I have been trying to follow this tutorial to create a nested tree view. The tutorial is in typescript while I am trying to do a similar thing in javascript with Angular2.
In the typescript code, the tree-view component looks like so:
import {Component, Input} from 'angular2/core';
import {Directory} from './directory';
#Component({
selector: 'tree-view',
templateUrl: './components/tree-view/tree-view.html',
directives: [TreeView]
})
export class TreeView {
#Input() directories: Array<Directory>;
}
In javascript that should convert to:
TreeView = ng.core
.Component({
selector: 'tree-view',
templateUrl: './components/tree-view/tree-view.html',
directives: [TreeView],
inputs: ['directory'],
})
.Class({
constructor: function() {
},
});
However, javascript throws the following error:
EXCEPTION: Unexpected directive value 'undefined' on the View of
component 'function () {'
I believe it's because I'm calling directives: [TreeView] before TreeView has been fully defined. If I remove that directive line, the error goes away. However, I don't know why it would work in typescript and not javascript if typescript simply compiles to javascript. This is the compiled javascript from the typescript code. I'm not sure what I'm missing. Any help would be super appreciated.
This question has been answered a few times
First of all classes are not hoisted. Quoting from MDN
An important difference between function declarations and class declarations is that function declarations are hoisted and class declarations are not. You first need to declare your class and then access it [...]
The documentation for forwardRef says
For instance, forwardRef is used when the token which we need to refer to for the purposes of DI is declared, but not yet defined. It is also used when the token which we use when creating a query is not yet defined.
So it's as easy as adding forwardRef to your code
directives : [ng.core.forwardRef(function() { return TreeView; })]
You can read more about this subject
Forward references in Angular 2
Others questions from StackOverflow