New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't retrieve attributes of the top-level component #1858

Open
anakinjay opened this Issue May 13, 2015 · 80 comments

Comments

@anakinjay

anakinjay commented May 13, 2015

http://plnkr.co/edit/5731Z9N6tQ391gQtfZrA?p=preview

I've been over the documentation 10 times, I've read through the source code, tutorials, the works... and I still can't wrap my head around what I'm doing wrong.

all I want to do is:

<app myTitle='my awesome title'>  

and access myTitle from inside the constructor.

Is that possible in NG2?

@vicb

This comment has been minimized.

Show comment
Hide comment
@vicb

vicb May 13, 2015

Contributor

In your example the myTitle property would only be available after the change detection has first runned, ie in the onChange event (you have to register to the onchange lifecycle hook), see the md button for an example.

If you need the value in the ctor, you would have to use @Attribute, the md checkbox for an example.

Contributor

vicb commented May 13, 2015

In your example the myTitle property would only be available after the change detection has first runned, ie in the onChange event (you have to register to the onchange lifecycle hook), see the md button for an example.

If you need the value in the ctor, you would have to use @Attribute, the md checkbox for an example.

@vicb vicb closed this May 13, 2015

@anakinjay

This comment has been minimized.

Show comment
Hide comment
@anakinjay

anakinjay May 15, 2015

Thanks but I still dont think it's working like it should. I have pretty much the most basic scenario, as you described, and still just does not work. No errors, but the attribute is null.

index.html

<!doctype html>
<html>
<head>
    <title>attribute test</title>

    <script src="https://github.jspm.io/jmcriffey/bower-traceur-runtime@0.0.87/traceur-runtime.js"></script>
    <script src="https://jspm.io/system@0.16.js"></script>
    <script src="https://code.angularjs.org/2.0.0-alpha.23/angular2.dev.js"></script>

</head>
<body>
    <app textname="text">Loading...</app>
    <script>

        System.import('app');
    </script>
</body>
</html>

app.ts

/// <reference path="../typings/angular2/angular2.d.ts" />

import {Component, bootstrap, View, Attribute} from 'angular2/angular2';


@Component({
  selector: 'app'
})
@View({
  template: '<h1>Hello {{ tt }}</h1>'
})
export class App {
  constructor(@Attribute("textname") tt) {

  console.log(tt);
  }
}

bootstrap(App);


anakinjay commented May 15, 2015

Thanks but I still dont think it's working like it should. I have pretty much the most basic scenario, as you described, and still just does not work. No errors, but the attribute is null.

index.html

<!doctype html>
<html>
<head>
    <title>attribute test</title>

    <script src="https://github.jspm.io/jmcriffey/bower-traceur-runtime@0.0.87/traceur-runtime.js"></script>
    <script src="https://jspm.io/system@0.16.js"></script>
    <script src="https://code.angularjs.org/2.0.0-alpha.23/angular2.dev.js"></script>

</head>
<body>
    <app textname="text">Loading...</app>
    <script>

        System.import('app');
    </script>
</body>
</html>

app.ts

/// <reference path="../typings/angular2/angular2.d.ts" />

import {Component, bootstrap, View, Attribute} from 'angular2/angular2';


@Component({
  selector: 'app'
})
@View({
  template: '<h1>Hello {{ tt }}</h1>'
})
export class App {
  constructor(@Attribute("textname") tt) {

  console.log(tt);
  }
}

bootstrap(App);


@vicb

This comment has been minimized.

Show comment
Hide comment
@vicb

vicb May 15, 2015

Contributor

You're right, it does not work on the top level component, re-opening

http://plnkr.co/edit/tLAv5uFH49t4o54HlQ0U?p=preview

Note that it works for nested Elements

Contributor

vicb commented May 15, 2015

You're right, it does not work on the top level component, re-opening

http://plnkr.co/edit/tLAv5uFH49t4o54HlQ0U?p=preview

Note that it works for nested Elements

@vicb vicb reopened this May 15, 2015

@vicb vicb changed the title from Can't retrieve properties of component to Can't retrieve attributes of the top-level component May 15, 2015

@aboeglin

This comment has been minimized.

Show comment
Hide comment
@aboeglin

aboeglin Aug 1, 2015

Any news or ETA for this one ? I just ran into this bug while trying to figure out property interpolation. In alpha 32 it is still present.

aboeglin commented Aug 1, 2015

Any news or ETA for this one ? I just ran into this bug while trying to figure out property interpolation. In alpha 32 it is still present.

@mhevery

This comment has been minimized.

Show comment
Hide comment
@mhevery

mhevery Aug 21, 2015

Member

Known issue. @vsavkin can you comment?

Member

mhevery commented Aug 21, 2015

Known issue. @vsavkin can you comment?

@singhamrinder

This comment has been minimized.

Show comment
Hide comment
@singhamrinder

singhamrinder Sep 4, 2015

Is their any workaround for this?

singhamrinder commented Sep 4, 2015

Is their any workaround for this?

@Mewel

This comment has been minimized.

Show comment
Hide comment
@Mewel

Mewel Sep 4, 2015

you can use the ElementRef:

constructor(public elementRef: ElementRef) {
    var native = this.elementRef.nativeElement;
    var myattr = native.getAttribute("myattr");
}

Mewel commented Sep 4, 2015

you can use the ElementRef:

constructor(public elementRef: ElementRef) {
    var native = this.elementRef.nativeElement;
    var myattr = native.getAttribute("myattr");
}
@tbosch

This comment has been minimized.

Show comment
Hide comment
@tbosch

tbosch Oct 27, 2015

Member

The reason why this is not working is that your index.html in which you place the <app myTitle='my awesome title'> is not an angular component. Because of this, Angular won't compile this element. And Angular does not read attribute values during runtime, only during compile time, as otherwise we would get a performance hit.

I.e. this works as intended, please use the code snippet that @Mewel described...

Member

tbosch commented Oct 27, 2015

The reason why this is not working is that your index.html in which you place the <app myTitle='my awesome title'> is not an angular component. Because of this, Angular won't compile this element. And Angular does not read attribute values during runtime, only during compile time, as otherwise we would get a performance hit.

I.e. this works as intended, please use the code snippet that @Mewel described...

@tbosch tbosch closed this Oct 27, 2015

@tbosch tbosch reopened this Oct 27, 2015

@tbosch

This comment has been minimized.

Show comment
Hide comment
@tbosch

tbosch Oct 27, 2015

Member

Let's leave this issue open so we can see how many people need this feature...

Member

tbosch commented Oct 27, 2015

Let's leave this issue open so we can see how many people need this feature...

@kbytesys

This comment has been minimized.

Show comment
Hide comment
@kbytesys

kbytesys Oct 27, 2015

Get attributes outside the angular app is useful because it's so easy to use them. If you won't provide this feature, just add some good documentation to address this use case.

Btw, reading attributes of the top-level component is easier to understand 😄

kbytesys commented Oct 27, 2015

Get attributes outside the angular app is useful because it's so easy to use them. If you won't provide this feature, just add some good documentation to address this use case.

Btw, reading attributes of the top-level component is easier to understand 😄

@anakinjay

This comment has been minimized.

Show comment
Hide comment
@anakinjay

anakinjay Oct 27, 2015

How big of a performance hit are we talking about here? If I'm building a single page app, I can understand why it's not a big deal...

but if I'm doing something like, building an interactive reusable user profile component to use in a wordpress theme or something, being able to just say is pretty important.

if it's cycling through all attributes that causes the hit, how about a flag attribute it can check? something like:

If import isn't set to true then it bypasses reading the properties?

Just a thought.

anakinjay commented Oct 27, 2015

How big of a performance hit are we talking about here? If I'm building a single page app, I can understand why it's not a big deal...

but if I'm doing something like, building an interactive reusable user profile component to use in a wordpress theme or something, being able to just say is pretty important.

if it's cycling through all attributes that causes the hit, how about a flag attribute it can check? something like:

If import isn't set to true then it bypasses reading the properties?

Just a thought.

@tbosch

This comment has been minimized.

Show comment
Hide comment
@tbosch

tbosch Oct 27, 2015

Member

To be clear: this only does not work when using a component as the root of
your application, I.e. Your application is the component. If you use this
component inside of an Angular app, this works fine.

Not reading this attribute is consistent with not interpreting [...] or
(...) attributes on the root element.
On Mon, Oct 26, 2015 at 5:58 PM anakinjay notifications@github.com wrote:

How big of a performance hit are we talking about here? If I'm building a
single page app, I can understand why it's not a big deal...

but if I'm doing something like, building an interactive reusable user
profile component to use in a wordpress theme or something, being able to
just say is pretty important.

if it's cycling through all attributes that causes the hit, how about a
flag attribute it can check? something like:

If import isn't set to true then it bypasses reading the properties?

Just a thought.


Reply to this email directly or view it on GitHub
#1858 (comment).

Member

tbosch commented Oct 27, 2015

To be clear: this only does not work when using a component as the root of
your application, I.e. Your application is the component. If you use this
component inside of an Angular app, this works fine.

Not reading this attribute is consistent with not interpreting [...] or
(...) attributes on the root element.
On Mon, Oct 26, 2015 at 5:58 PM anakinjay notifications@github.com wrote:

How big of a performance hit are we talking about here? If I'm building a
single page app, I can understand why it's not a big deal...

but if I'm doing something like, building an interactive reusable user
profile component to use in a wordpress theme or something, being able to
just say is pretty important.

if it's cycling through all attributes that causes the hit, how about a
flag attribute it can check? something like:

If import isn't set to true then it bypasses reading the properties?

Just a thought.


Reply to this email directly or view it on GitHub
#1858 (comment).

@tbosch

This comment has been minimized.

Show comment
Hide comment
@tbosch

tbosch Oct 27, 2015

Member

This feature would require a lot of special cases / code paths:

  • special change defectors for root components, as the regular ones are
    precompiled into code during a build step soon and don't know where an app
    gets bootstrapped.
  • special "readAttributes" method in the renderer API, as Angular is
    running on NativeScript and WebWorkers too.

On Mon, Oct 26, 2015 at 6:14 PM Tobias Bosch tbosch@google.com wrote:

To be clear: this only does not work when using a component as the root of
your application, I.e. Your application is the component. If you use this
component inside of an Angular app, this works fine.

Not reading this attribute is consistent with not interpreting [...] or
(...) attributes on the root element.
On Mon, Oct 26, 2015 at 5:58 PM anakinjay notifications@github.com
wrote:

How big of a performance hit are we talking about here? If I'm building a
single page app, I can understand why it's not a big deal...

but if I'm doing something like, building an interactive reusable user
profile component to use in a wordpress theme or something, being able to
just say is pretty important.

if it's cycling through all attributes that causes the hit, how about a
flag attribute it can check? something like:

If import isn't set to true then it bypasses reading the properties?

Just a thought.


Reply to this email directly or view it on GitHub
#1858 (comment).

Member

tbosch commented Oct 27, 2015

This feature would require a lot of special cases / code paths:

  • special change defectors for root components, as the regular ones are
    precompiled into code during a build step soon and don't know where an app
    gets bootstrapped.
  • special "readAttributes" method in the renderer API, as Angular is
    running on NativeScript and WebWorkers too.

On Mon, Oct 26, 2015 at 6:14 PM Tobias Bosch tbosch@google.com wrote:

To be clear: this only does not work when using a component as the root of
your application, I.e. Your application is the component. If you use this
component inside of an Angular app, this works fine.

Not reading this attribute is consistent with not interpreting [...] or
(...) attributes on the root element.
On Mon, Oct 26, 2015 at 5:58 PM anakinjay notifications@github.com
wrote:

How big of a performance hit are we talking about here? If I'm building a
single page app, I can understand why it's not a big deal...

but if I'm doing something like, building an interactive reusable user
profile component to use in a wordpress theme or something, being able to
just say is pretty important.

if it's cycling through all attributes that causes the hit, how about a
flag attribute it can check? something like:

If import isn't set to true then it bypasses reading the properties?

Just a thought.


Reply to this email directly or view it on GitHub
#1858 (comment).

@jimmymain

This comment has been minimized.

Show comment
Hide comment
@jimmymain

jimmymain Nov 15, 2016

@robwormald, could you post an example for multiple bootstrapped angular components on a page using the new module syntax, with imports from @angular/platform-browser-dynamic and platformBrowserDynamic().bootstrapModule(AppModule);
. Your example is outdated. I have posted a similar question here, but alas no workable answers since it was posted.

jimmymain commented Nov 15, 2016

@robwormald, could you post an example for multiple bootstrapped angular components on a page using the new module syntax, with imports from @angular/platform-browser-dynamic and platformBrowserDynamic().bootstrapModule(AppModule);
. Your example is outdated. I have posted a similar question here, but alas no workable answers since it was posted.

@DzmitryShylovich

This comment has been minimized.

Show comment
Hide comment
Contributor

DzmitryShylovich commented Nov 15, 2016

@jimmymain

This comment has been minimized.

Show comment
Hide comment
@jimmymain

jimmymain Nov 15, 2016

thanks, the obvious solution didn't occur to me. I have been staring at it too long, couldn't see the wood for the trees...

jimmymain commented Nov 15, 2016

thanks, the obvious solution didn't occur to me. I have been staring at it too long, couldn't see the wood for the trees...

@robgha01

This comment has been minimized.

Show comment
Hide comment
@robgha01

robgha01 Nov 29, 2016

Im looking for a way to use this with razor its a server side processor it outputs html im using umbraco.
my problem is the root component cant use existing html that my razor file has outputed leading me to the next question as i came here from all other related issues.

How am i supposed to intrigate my body with existing html as we used in angular 1 with ng-controller. if this is not possible then i will have to drop angular 2 complitly... ?

Edit: i found this hack that im using until this is resolved. http://stackoverflow.com/questions/34993936/angular-2-it-is-possible-to-bind-the-app-component-in-existing-dom-without-era

robgha01 commented Nov 29, 2016

Im looking for a way to use this with razor its a server side processor it outputs html im using umbraco.
my problem is the root component cant use existing html that my razor file has outputed leading me to the next question as i came here from all other related issues.

How am i supposed to intrigate my body with existing html as we used in angular 1 with ng-controller. if this is not possible then i will have to drop angular 2 complitly... ?

Edit: i found this hack that im using until this is resolved. http://stackoverflow.com/questions/34993936/angular-2-it-is-possible-to-bind-the-app-component-in-existing-dom-without-era

@jimmymain

This comment has been minimized.

Show comment
Hide comment
@jimmymain

jimmymain Nov 30, 2016

@robgha01 ng-content is not supported on a root component, so in short you cannot do it. angular 2 is not designed in the same way as angular1. My experience suggests that if you are not writing a single page app, stick with angular1 or choose a different framework.

jimmymain commented Nov 30, 2016

@robgha01 ng-content is not supported on a root component, so in short you cannot do it. angular 2 is not designed in the same way as angular1. My experience suggests that if you are not writing a single page app, stick with angular1 or choose a different framework.

@robgha01

This comment has been minimized.

Show comment
Hide comment
@robgha01

robgha01 Nov 30, 2016

@jimmymain Not really helpfull are ya...

Im writing a website application but i need to embed serverside template and that means root component need to support and allow this becuse we can not tell razor to output things after becuse razor is a server language and not used at client side meaning if you have no knowlage of serverside wich i see when you write that nonesence you clearly dont know what im refering to or how a website application work in a real world not in a local or html only site we are not in the 70th this is 2016!

Stick with legecy systems is not recomended.... if everyone follows that rule i would have windows 95 installed on this computer....

and if angular2 will not support the users then its garbage.
if you have no common sense in what a user write dont answer it... im offended by what you wrote.

robgha01 commented Nov 30, 2016

@jimmymain Not really helpfull are ya...

Im writing a website application but i need to embed serverside template and that means root component need to support and allow this becuse we can not tell razor to output things after becuse razor is a server language and not used at client side meaning if you have no knowlage of serverside wich i see when you write that nonesence you clearly dont know what im refering to or how a website application work in a real world not in a local or html only site we are not in the 70th this is 2016!

Stick with legecy systems is not recomended.... if everyone follows that rule i would have windows 95 installed on this computer....

and if angular2 will not support the users then its garbage.
if you have no common sense in what a user write dont answer it... im offended by what you wrote.

@jimmymain

This comment has been minimized.

Show comment
Hide comment
@jimmymain

jimmymain Nov 30, 2016

@robgha01 had no wish to be offensive. I also build angular 1 applications using c# ASP.NET and MVC. I do know what you are referring to. I am simply trying to point out that angular 2 is not built this way. Again terribly sorry if you found my response offensive. I wish I could be of more assistance, but I don't think you are going to find that angular 2 will suit your particular (albeit common) style. My suspicion is that you will need to use angular 2 differently. I am happy to be corrected or proven wrong, but my suspicion is that you will need to embrace the angular 2 approach - and leverage your razor views as partial views, obtained through angular controller calls and angular directives. ng-content is not supported (as yet) by root components. I am sorry I can't help further. The reason I responded at all is that I have felt the same frustration attempting to migrate to angular2.

As @coli said, the only way he has managed to achieve this at all is using the angular migration components, which doesn't give anyone encouragement that this style is around to stay. He's worried about getting burned going down this route - and I would concur.

jimmymain commented Nov 30, 2016

@robgha01 had no wish to be offensive. I also build angular 1 applications using c# ASP.NET and MVC. I do know what you are referring to. I am simply trying to point out that angular 2 is not built this way. Again terribly sorry if you found my response offensive. I wish I could be of more assistance, but I don't think you are going to find that angular 2 will suit your particular (albeit common) style. My suspicion is that you will need to use angular 2 differently. I am happy to be corrected or proven wrong, but my suspicion is that you will need to embrace the angular 2 approach - and leverage your razor views as partial views, obtained through angular controller calls and angular directives. ng-content is not supported (as yet) by root components. I am sorry I can't help further. The reason I responded at all is that I have felt the same frustration attempting to migrate to angular2.

As @coli said, the only way he has managed to achieve this at all is using the angular migration components, which doesn't give anyone encouragement that this style is around to stay. He's worried about getting burned going down this route - and I would concur.

@robgha01

This comment has been minimized.

Show comment
Hide comment
@robgha01

robgha01 Nov 30, 2016

@jimmymain I guess i exploded a bit sorry for that im really frustrated now. to only use partials will be to mush of a implamentation as im using a cms already il just have to hack my way and hope that my head wont explode its not much left until it falls appart.

I have managed to use this

import { Component } from "@angular/core";

/**
 * This is a hack taken from http://stackoverflow.com/questions/34993936/angular-2-it-is-possible-to-bind-the-app-component-in-existing-dom-without-era
 * @param tagName
 */
function getExistingContentByTag(tagName) {
    var target = document.getElementsByTagName(tagName)[0];

    if (!target || !target.tagName) return "";

    return target.innerHTML;
}

@Component({
    selector: "body", // this will ensure that angular controlls the whole page with only one root component.
    template: getExistingContentByTag("body") // Currently we have no way of using existing html as per to https://github.com/angular/angular/issues/1858 so we use this hack.
})
export class AppComponent { }

and it seams to work but i now get another error that i just cant figure out i dont know if its related or not but it follows as:
metadata_resolver.js:623Uncaught Error: Can't resolve all parameters for HighlightDirective: (?, ?).(…)CompileMetadataResolver._getDependenciesMetadata @ metadata_resolver.js:623CompileMetadataResolver._getTypeMetadata @ metadata_resolver.js:517CompileMetadataResolver.getNonNormalizedDirectiveMetadata @ metadata_resolver.js:255CompileMetadataResolver._loadDirectiveMetadata @ metadata_resolver.js:134(anonymous function) @ metadata_resolver.js:400(anonymous function) @ metadata_resolver.js:315CompileMetadataResolver.loadNgModuleMetadata @ metadata_resolver.js:315RuntimeCompiler._loadModules @ runtime_compiler.js:99RuntimeCompiler._compileModuleAndComponents @ runtime_compiler.js:69RuntimeCompiler.compileModuleAsync @ runtime_compiler.js:59PlatformRef_._bootstrapModuleWithZone @ application_ref.js:302PlatformRef_.bootstrapModule @ application_ref.js:284(anonymous function) @ Wella.ts:5__webpack_require__ @ bootstrap 6ca6f18…:19(anonymous function) @ zone.js:1426__webpack_require__ @ bootstrap 6ca6f18…:19(anonymous function) @ bootstrap 6ca6f18…:63(anonymous function) @ bootstrap 6ca6f18…:63

i followed the angular guide here "https://angular.io/docs/ts/latest/guide/attribute-directives.html#!#write-directive" xD

robgha01 commented Nov 30, 2016

@jimmymain I guess i exploded a bit sorry for that im really frustrated now. to only use partials will be to mush of a implamentation as im using a cms already il just have to hack my way and hope that my head wont explode its not much left until it falls appart.

I have managed to use this

import { Component } from "@angular/core";

/**
 * This is a hack taken from http://stackoverflow.com/questions/34993936/angular-2-it-is-possible-to-bind-the-app-component-in-existing-dom-without-era
 * @param tagName
 */
function getExistingContentByTag(tagName) {
    var target = document.getElementsByTagName(tagName)[0];

    if (!target || !target.tagName) return "";

    return target.innerHTML;
}

@Component({
    selector: "body", // this will ensure that angular controlls the whole page with only one root component.
    template: getExistingContentByTag("body") // Currently we have no way of using existing html as per to https://github.com/angular/angular/issues/1858 so we use this hack.
})
export class AppComponent { }

and it seams to work but i now get another error that i just cant figure out i dont know if its related or not but it follows as:
metadata_resolver.js:623Uncaught Error: Can't resolve all parameters for HighlightDirective: (?, ?).(…)CompileMetadataResolver._getDependenciesMetadata @ metadata_resolver.js:623CompileMetadataResolver._getTypeMetadata @ metadata_resolver.js:517CompileMetadataResolver.getNonNormalizedDirectiveMetadata @ metadata_resolver.js:255CompileMetadataResolver._loadDirectiveMetadata @ metadata_resolver.js:134(anonymous function) @ metadata_resolver.js:400(anonymous function) @ metadata_resolver.js:315CompileMetadataResolver.loadNgModuleMetadata @ metadata_resolver.js:315RuntimeCompiler._loadModules @ runtime_compiler.js:99RuntimeCompiler._compileModuleAndComponents @ runtime_compiler.js:69RuntimeCompiler.compileModuleAsync @ runtime_compiler.js:59PlatformRef_._bootstrapModuleWithZone @ application_ref.js:302PlatformRef_.bootstrapModule @ application_ref.js:284(anonymous function) @ Wella.ts:5__webpack_require__ @ bootstrap 6ca6f18…:19(anonymous function) @ zone.js:1426__webpack_require__ @ bootstrap 6ca6f18…:19(anonymous function) @ bootstrap 6ca6f18…:63(anonymous function) @ bootstrap 6ca6f18…:63

i followed the angular guide here "https://angular.io/docs/ts/latest/guide/attribute-directives.html#!#write-directive" xD

@jimmymain

This comment has been minimized.

Show comment
Hide comment
@jimmymain

jimmymain Nov 30, 2016

@robgha01 no problem, best of luck, and if you manage to get something working, let us know. I used angular 1 to supplement my existing application. angular 2 seems to be a very complete framework designed to be the core of the application, not something that is easily tacked onto an existing application. Let's hope it changes in such a way that we can still leverage it. Either that, or we have to change our approach.

jimmymain commented Nov 30, 2016

@robgha01 no problem, best of luck, and if you manage to get something working, let us know. I used angular 1 to supplement my existing application. angular 2 seems to be a very complete framework designed to be the core of the application, not something that is easily tacked onto an existing application. Let's hope it changes in such a way that we can still leverage it. Either that, or we have to change our approach.

@robgha01

This comment has been minimized.

Show comment
Hide comment
@robgha01

robgha01 Nov 30, 2016

i think it relates to the import but im not really sure

import { Directive, ElementRef, Input, Renderer } from '@angular/core';
@Directive({ selector: '[myHighlight]' })
export class HighlightDirective {
    constructor(el: ElementRef, renderer: Renderer) {
        renderer.setElementStyle(el.nativeElement, 'backgroundColor', 'yellow');
    }
}

robgha01 commented Nov 30, 2016

i think it relates to the import but im not really sure

import { Directive, ElementRef, Input, Renderer } from '@angular/core';
@Directive({ selector: '[myHighlight]' })
export class HighlightDirective {
    constructor(el: ElementRef, renderer: Renderer) {
        renderer.setElementStyle(el.nativeElement, 'backgroundColor', 'yellow');
    }
}
@robgha01

This comment has been minimized.

Show comment
Hide comment
@robgha01

robgha01 Nov 30, 2016

@jimmymain ok i managed to get it working xD i guess im just to new to angular2
i changed this
<h1 sticynavbar>Hej!</h1> to

<sticynavbar>
        <h1 sticynavbar>Hi!</h1>
    </sticynavbar>

and now the constructor and everyting is triggering... is there no way to only use "
<h1 sticynavbar>Hej!</h1>" ?

robgha01 commented Nov 30, 2016

@jimmymain ok i managed to get it working xD i guess im just to new to angular2
i changed this
<h1 sticynavbar>Hej!</h1> to

<sticynavbar>
        <h1 sticynavbar>Hi!</h1>
    </sticynavbar>

and now the constructor and everyting is triggering... is there no way to only use "
<h1 sticynavbar>Hej!</h1>" ?

@blackpr

This comment has been minimized.

Show comment
Hide comment
@blackpr

blackpr Dec 1, 2016

Maybe this is offtopic but..
I came here because i wanted to use Angular 2 with Laravel.
Here is how i did it.

I have my server side language (php) and i want some pages to use Angular.
Also I want to have one js file minified and everything that angular cli does.
The routing is done only on the server.
To achieve that I have my own conventions.
The pages that will use Angular 2 will have a specific path. Lets say [host]/pages/appModule, [host]/pages/testModule etc.

Then I have a functions that checks the url and find the module that I want. Lets name it src/app/findModule.ts

import { AppModule } from './';
import { TestModule } from './test.module';

export default () => {
  let module;
  let windowLocation = window.location.pathname;
  let locationArray = windowLocation.split('/');

  if(locationArray[1]=='pages') {

    if(locationArray[2]){
      switch (locationArray[2]) {

        case 'TestModule':
          module = TestModule;
          break;
        default:
          module = AppModule;
          break;
      }

    }
  } else {
    module = AppModule;
  }
  return module;
}

(Yes this function can be better and more dynamic. lets keep it for now)

Then I import it in main.ts

import findModule from './app/findModule'

and use it to bootstrap my application like this

platformBrowserDynamic().bootstrapModule(findModule());

So every server page that uses Angular has its own root ngModule and its own independent component tree.

Every time that i have a new page i create an new root ngModule and a new component and just update the switch in findModule.ts

Now say that we have the src/test.module.ts

@NgModule({
  declarations: [
    TestComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [],
  bootstrap: [TestComponent]
})
export class TestModule { }

and the src/test/test.component.ts

import { Component, OnInit, Input, ElementRef } from '@angular/core';

@Component({
  selector: 'app-test',
  template: `--- {{test | json}}  ---`,
  styleUrls: ['./test.component.css']
})
export class TestComponent implements OnInit {
  test: string;
  constructor(private el: ElementRef) {
    var native = this.el.nativeElement;
    this.test = JSON.parse(native.getAttribute("test"));
  }

  ngOnInit() {
    console.log(this.test);
  }

}

Now in html we can use something like this

<app-test test='[{"name": "blackpr"}]'></app-test>

blackpr commented Dec 1, 2016

Maybe this is offtopic but..
I came here because i wanted to use Angular 2 with Laravel.
Here is how i did it.

I have my server side language (php) and i want some pages to use Angular.
Also I want to have one js file minified and everything that angular cli does.
The routing is done only on the server.
To achieve that I have my own conventions.
The pages that will use Angular 2 will have a specific path. Lets say [host]/pages/appModule, [host]/pages/testModule etc.

Then I have a functions that checks the url and find the module that I want. Lets name it src/app/findModule.ts

import { AppModule } from './';
import { TestModule } from './test.module';

export default () => {
  let module;
  let windowLocation = window.location.pathname;
  let locationArray = windowLocation.split('/');

  if(locationArray[1]=='pages') {

    if(locationArray[2]){
      switch (locationArray[2]) {

        case 'TestModule':
          module = TestModule;
          break;
        default:
          module = AppModule;
          break;
      }

    }
  } else {
    module = AppModule;
  }
  return module;
}

(Yes this function can be better and more dynamic. lets keep it for now)

Then I import it in main.ts

import findModule from './app/findModule'

and use it to bootstrap my application like this

platformBrowserDynamic().bootstrapModule(findModule());

So every server page that uses Angular has its own root ngModule and its own independent component tree.

Every time that i have a new page i create an new root ngModule and a new component and just update the switch in findModule.ts

Now say that we have the src/test.module.ts

@NgModule({
  declarations: [
    TestComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [],
  bootstrap: [TestComponent]
})
export class TestModule { }

and the src/test/test.component.ts

import { Component, OnInit, Input, ElementRef } from '@angular/core';

@Component({
  selector: 'app-test',
  template: `--- {{test | json}}  ---`,
  styleUrls: ['./test.component.css']
})
export class TestComponent implements OnInit {
  test: string;
  constructor(private el: ElementRef) {
    var native = this.el.nativeElement;
    this.test = JSON.parse(native.getAttribute("test"));
  }

  ngOnInit() {
    console.log(this.test);
  }

}

Now in html we can use something like this

<app-test test='[{"name": "blackpr"}]'></app-test>
@wardbell

This comment has been minimized.

Show comment
Hide comment
@wardbell

wardbell Dec 1, 2016

Contributor

FYI, the index.html that hosts your top-level component (typically AppComponent) is not a component template! All of that HTML is invisible to your Angular 2 application.

That means the Angular 2 techniques you know for extracting template information (including attribute assignment) do not work in that context.

You have to switch to old-school DOM querying techniques to extract information that is inside the index.html but outside the scope of your Angular application component.

This is different from Angular 1. Fortunately, once you know about this difference, you should be able to get what you need.

We intend to document this in the not distant future.

Contributor

wardbell commented Dec 1, 2016

FYI, the index.html that hosts your top-level component (typically AppComponent) is not a component template! All of that HTML is invisible to your Angular 2 application.

That means the Angular 2 techniques you know for extracting template information (including attribute assignment) do not work in that context.

You have to switch to old-school DOM querying techniques to extract information that is inside the index.html but outside the scope of your Angular application component.

This is different from Angular 1. Fortunately, once you know about this difference, you should be able to get what you need.

We intend to document this in the not distant future.

@maxime-menard

This comment has been minimized.

Show comment
Hide comment
@maxime-menard

maxime-menard Dec 8, 2016

Hi,
I'm trying to integrate angular 2 in existing application.
So similar than @blackpr but I wanted to know if it's possible to use the router instead of creating root module for every main component. Is it possible to display a component by giving the component name to the root component :

<my-app displayComponent="myComponent">Loading...</my-app>

And then use the router to display the component myComponent ?
I can retrieve the componentToDisplay property in the root component like @blackpr did, but then it does not work when I try to navigate to the component myComponent.

export class AppComponent implements OnInit {

  displayComponent: string;

  constructor(private router: Router, private elm: ElementRef) {
    this.displayComponent = elm.nativeElement.getAttribute('displayComponent');
  }

  ngOnInit(): void {
    this.router.navigate([this.displayComponent]);
  }
}

Thanks

maxime-menard commented Dec 8, 2016

Hi,
I'm trying to integrate angular 2 in existing application.
So similar than @blackpr but I wanted to know if it's possible to use the router instead of creating root module for every main component. Is it possible to display a component by giving the component name to the root component :

<my-app displayComponent="myComponent">Loading...</my-app>

And then use the router to display the component myComponent ?
I can retrieve the componentToDisplay property in the root component like @blackpr did, but then it does not work when I try to navigate to the component myComponent.

export class AppComponent implements OnInit {

  displayComponent: string;

  constructor(private router: Router, private elm: ElementRef) {
    this.displayComponent = elm.nativeElement.getAttribute('displayComponent');
  }

  ngOnInit(): void {
    this.router.navigate([this.displayComponent]);
  }
}

Thanks

@zoechi

This comment has been minimized.

Show comment
Hide comment
@zoechi

zoechi Dec 8, 2016

Contributor

@maxime-menard
GitHub issues are for bug reports and feature requests.
For support questions please use other channels like the ones listed in CONTRIBUTING - Got a Question or Problem?

Contributor

zoechi commented Dec 8, 2016

@maxime-menard
GitHub issues are for bug reports and feature requests.
For support questions please use other channels like the ones listed in CONTRIBUTING - Got a Question or Problem?

@Oceanswave

This comment has been minimized.

Show comment
Hide comment
@Oceanswave

Oceanswave commented Feb 27, 2017

+1

@blteblte

This comment has been minimized.

Show comment
Hide comment
@blteblte

blteblte Apr 6, 2017

I see all these workarounds, but has anyone thought about how would you do this on server side, where you have no DOM and the only variable scope you have is in a context of pre-renderer?

blteblte commented Apr 6, 2017

I see all these workarounds, but has anyone thought about how would you do this on server side, where you have no DOM and the only variable scope you have is in a context of pre-renderer?

@zoechi

This comment has been minimized.

Show comment
Hide comment
@zoechi

zoechi Apr 6, 2017

Contributor

@blteblte what about providing and injecting?

Contributor

zoechi commented Apr 6, 2017

@blteblte what about providing and injecting?

@blteblte

This comment has been minimized.

Show comment
Hide comment
@blteblte

blteblte Apr 7, 2017

@zoechi - I guess I do not understand something... providing and injecting where?

<app somevar="@someVar" asp-prerender-module="ClientApp/dist/main-server">Loading...</app>
//...
const platform = platformNodeDynamic();
//...
return requestZone.run<Promise<string>>(() => platform.serializeModule(AppModule)).then(html => {
    resolve({ html: html });
}, reject);

What I meant is that all workarounds I could find here are client side, f.e this:

constructor(private el: ElementRef) {
    const native = this.el.nativeElement;
    const someVar = native.getAttribute("somevar");
}

... wont work when prerendering on server.

The Only Way (or am I wrong?) you can get this 'somevar' on server pre-render stage is via api request - but that's offtopic.

Thing is - is there a workaround to get <app somevar="@someVar" ... server-side (i guess - no)?

constructor() {
    if (!isBrowser) {
        //...
    }
}

blteblte commented Apr 7, 2017

@zoechi - I guess I do not understand something... providing and injecting where?

<app somevar="@someVar" asp-prerender-module="ClientApp/dist/main-server">Loading...</app>
//...
const platform = platformNodeDynamic();
//...
return requestZone.run<Promise<string>>(() => platform.serializeModule(AppModule)).then(html => {
    resolve({ html: html });
}, reject);

What I meant is that all workarounds I could find here are client side, f.e this:

constructor(private el: ElementRef) {
    const native = this.el.nativeElement;
    const someVar = native.getAttribute("somevar");
}

... wont work when prerendering on server.

The Only Way (or am I wrong?) you can get this 'somevar' on server pre-render stage is via api request - but that's offtopic.

Thing is - is there a workaround to get <app somevar="@someVar" ... server-side (i guess - no)?

constructor() {
    if (!isBrowser) {
        //...
    }
}
@zoechi

This comment has been minimized.

Show comment
Hide comment
@zoechi

zoechi Apr 7, 2017

Contributor

@blteblte GitHub issues are for bug reports and feature requests.
For support questions please use other channels like the ones listed in CONTRIBUTING - Got a Question or Problem?

Contributor

zoechi commented Apr 7, 2017

@blteblte GitHub issues are for bug reports and feature requests.
For support questions please use other channels like the ones listed in CONTRIBUTING - Got a Question or Problem?

@anakinjay

This comment has been minimized.

Show comment
Hide comment
@anakinjay

anakinjay Jul 10, 2017

I'm shocked that this is still an issue. Years ago when I submitted this, this issue caused our entire business to ditch angular 2 and use react for everything. Which has worked fantastic for years, but now we have a project that requires NG2 and here I am literally two years later faced with the same problem.

That being said, I came up with a hokey work around. I have no idea how bad this is as far as hokey factor and I'm sure it's not very performant, but i wanted to share in case it helps someone.

(this assumes you give your root component the id of "approot" in your index.html file)

app.component.ts:

  ngOnInit() {
     let attrs = document.getElementById("approot").attributes;
     Object.keys(attrs).forEach(key => {
     this[attrs[key].name] = attrs[key].value;
  });

I know it could be optimized, but this is a nice easy copy and paste thing for us to throw into app.component.ts and then not have to worry about changing anything if we later decide we need to add or modify root level attributes.

Hope this helps!

anakinjay commented Jul 10, 2017

I'm shocked that this is still an issue. Years ago when I submitted this, this issue caused our entire business to ditch angular 2 and use react for everything. Which has worked fantastic for years, but now we have a project that requires NG2 and here I am literally two years later faced with the same problem.

That being said, I came up with a hokey work around. I have no idea how bad this is as far as hokey factor and I'm sure it's not very performant, but i wanted to share in case it helps someone.

(this assumes you give your root component the id of "approot" in your index.html file)

app.component.ts:

  ngOnInit() {
     let attrs = document.getElementById("approot").attributes;
     Object.keys(attrs).forEach(key => {
     this[attrs[key].name] = attrs[key].value;
  });

I know it could be optimized, but this is a nice easy copy and paste thing for us to throw into app.component.ts and then not have to worry about changing anything if we later decide we need to add or modify root level attributes.

Hope this helps!

@tekkemphani

This comment has been minimized.

Show comment
Hide comment
@tekkemphani

tekkemphani Dec 28, 2017

Just import ElementRef
import { Component,Input,ElementRef } from '@angular/core';

@component({
selector: 'my-app',
template: `

Hello {{title}}

` }) export class AppComponent { constructor(public elemRef:ElementRef) { this.title = this.elemRef.nativeElement.getAttribute("title"); } }

file: Index.html

tekkemphani commented Dec 28, 2017

Just import ElementRef
import { Component,Input,ElementRef } from '@angular/core';

@component({
selector: 'my-app',
template: `

Hello {{title}}

` }) export class AppComponent { constructor(public elemRef:ElementRef) { this.title = this.elemRef.nativeElement.getAttribute("title"); } }

file: Index.html

@ngbot ngbot bot added this to the Backlog milestone Jan 23, 2018

@mhevery

This comment has been minimized.

Show comment
Hide comment
@mhevery

mhevery Jul 25, 2018

Member

This issue will have much simpler implementation with Ivy.

Member

mhevery commented Jul 25, 2018

This issue will have much simpler implementation with Ivy.

@alexmatv70

This comment has been minimized.

Show comment
Hide comment
@alexmatv70

alexmatv70 Aug 7, 2018

I am faced this problem too. In my case it is not a top-level component, but @input property was always undefined. I've tried component-interaction demo and it worked. I've decreased angular version from 6.0.3 to 6.0.0 hoping this is a version bug and without success.
@input started to work when I changed parent componet template that references child component from
<app-albums-view [cat]="recent"></app-albums-view>
to
<app-albums-view cat="recent"></app-albums-view>

I suppose there is some bug that need to be fixed. I've spent about a day trying to make it work and still don't undestand why first version doesn't work.
I have Windows 10 Home version 1803.
npm 5.6.0
Hoping this info will help to fix this bug.
Thanks.

alexmatv70 commented Aug 7, 2018

I am faced this problem too. In my case it is not a top-level component, but @input property was always undefined. I've tried component-interaction demo and it worked. I've decreased angular version from 6.0.3 to 6.0.0 hoping this is a version bug and without success.
@input started to work when I changed parent componet template that references child component from
<app-albums-view [cat]="recent"></app-albums-view>
to
<app-albums-view cat="recent"></app-albums-view>

I suppose there is some bug that need to be fixed. I've spent about a day trying to make it work and still don't undestand why first version doesn't work.
I have Windows 10 Home version 1803.
npm 5.6.0
Hoping this info will help to fix this bug.
Thanks.

@truestbyheart

This comment has been minimized.

Show comment
Hide comment
@truestbyheart

truestbyheart Sep 17, 2018

okay,guys i recently run int the same problem and after a long search i decided to mix my ideas and ended up with the following.
1.declare an array object of the data you want to pass like
private sendMe: Array<{title: string}> = [];

2.push the data you want to send to the array like
this.sendMe.push({title: this.passMe});

3 and atlast pass the array like
<app-download-section [movieTitle]="sendMe"></app-download-section>

  1. recieve it like
import { Component, OnInit, OnDestroy, Input } from '@angular/core';

@Component({
  selector: 'app-download-section',
  templateUrl: './download-section.component.html',
  styleUrls: ['./download-section.component.css']
})
export class DownloadSectionComponent implements OnInit {

  @Input('movieTitle') movieTitle: Array<object> = [];
  constructor() { }

  ngOnInit() {
    console.log(this.movieTitle);
  }
  // tslint:disable-next-line:use-life-cycle-interface
  ngOnDestroy() {

  }

}

truestbyheart commented Sep 17, 2018

okay,guys i recently run int the same problem and after a long search i decided to mix my ideas and ended up with the following.
1.declare an array object of the data you want to pass like
private sendMe: Array<{title: string}> = [];

2.push the data you want to send to the array like
this.sendMe.push({title: this.passMe});

3 and atlast pass the array like
<app-download-section [movieTitle]="sendMe"></app-download-section>

  1. recieve it like
import { Component, OnInit, OnDestroy, Input } from '@angular/core';

@Component({
  selector: 'app-download-section',
  templateUrl: './download-section.component.html',
  styleUrls: ['./download-section.component.css']
})
export class DownloadSectionComponent implements OnInit {

  @Input('movieTitle') movieTitle: Array<object> = [];
  constructor() { }

  ngOnInit() {
    console.log(this.movieTitle);
  }
  // tslint:disable-next-line:use-life-cycle-interface
  ngOnDestroy() {

  }

}
@isotope3

This comment has been minimized.

Show comment
Hide comment
@isotope3

isotope3 Sep 20, 2018

This issue bites you specially when you are trying to create an Angular Custom Element (Angular Element) and not a full fledged app.

Say you want to create an element like <card-element></card-element> , you would want to pass values to this elements using attributes eg

<card-element 
    title="Card title"
    text="Sample text for the card"
   imgurl="/title.png"
   link="http://somewhere.com/"
  linktext="Somewhere"
> </card-element>

While creating this element in Angular (say Angular 6), the obvious assumption is you can retrofit app-component for this element and try to test it first with <app-root></app-root> by doing something like

<app-root 
title="Card title"
text="Sample text for the card"
imgurl="/title.png"
link="http://somewhere.com/"
linktext="Somewhere">
</app-root>

And bam! It doesn't work. App component is not getting the attributes, but you would have expected it otherwise. So you cant see how your element is going to work.

If you blindly go through the whole process of creating the Angular Element (https://angular.io/guide/elements) and then test your element in an html page, the new Angular Element works fine even though the attributes are being passed in root component.

Magic!

Eagerly waiting for Ivy!

isotope3 commented Sep 20, 2018

This issue bites you specially when you are trying to create an Angular Custom Element (Angular Element) and not a full fledged app.

Say you want to create an element like <card-element></card-element> , you would want to pass values to this elements using attributes eg

<card-element 
    title="Card title"
    text="Sample text for the card"
   imgurl="/title.png"
   link="http://somewhere.com/"
  linktext="Somewhere"
> </card-element>

While creating this element in Angular (say Angular 6), the obvious assumption is you can retrofit app-component for this element and try to test it first with <app-root></app-root> by doing something like

<app-root 
title="Card title"
text="Sample text for the card"
imgurl="/title.png"
link="http://somewhere.com/"
linktext="Somewhere">
</app-root>

And bam! It doesn't work. App component is not getting the attributes, but you would have expected it otherwise. So you cant see how your element is going to work.

If you blindly go through the whole process of creating the Angular Element (https://angular.io/guide/elements) and then test your element in an html page, the new Angular Element works fine even though the attributes are being passed in root component.

Magic!

Eagerly waiting for Ivy!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment