Efe
Efe

Reputation: 880

direct binding to a property of property in Angular

I have a model like this:

export class Person{
name: string;
}

Which is used in my component as follow:

export class TestComponent {
  @Input() person : Person;
  constructor() {
  }
}

I want to set person name from html as below:

<app-test [person.name]="'Jack'"</app-test>

When I do so, angular gets angry that : "Can't bind to 'person.name' since it isn't a known property of 'app-test'."

well, he is right somehow, person is property of my component, not person.name

On the other hand, we don't get any error in following sample:

<span [style.color]="'red'">This span is red.</span>

Am I moving against rules??

Or is style property internally different? How?

Thanks

Upvotes: 2

Views: 2713

Answers (4)

Nikola Stekovic
Nikola Stekovic

Reputation: 635

That is because style is directive with multiple selectors and inputs.

You can achieve this by having some directive that would do the job. I guess you could make something similar to this: (Not tested)

import { Directive, ViewContainerRef, ChangeDetectorRef, OnInit } from '@angular/core';

const selector = `
  [name],
  [name.foo],
  [name.bar]
`;

export const inputs = [
  'name',
  'name.foo',
  'name.bar'
];



@Directive({
  selector,
  inputs
})
export class HelloDirective implements OnInit {
  constructor(
    private viewContainerRef: ViewContainerRef
  ) {
  }

  ngOnInit(): void {
    const getSetKeys = Object.keys(this).filter(item => inputs.indexOf(item) > -1);
    const getValues = getSetKeys.map(item => this[item]);
    const component = this.viewContainerRef['_view'].component;
    getSetKeys.forEach((item, index) => {
      const splitKey = item.split('.');
      component[splitKey[0]][splitKey[1]] = getValues[index];
    })
  }
}

In this case, you could use your directive as <some-component [name.foo]="'Some foo'" [name.bar]="'Some bar'"></some-component> and this would inject to your "name" object in component.

I would not recommend this way but it is possible to implement it.

Upvotes: 0

devBrandon
devBrandon

Reputation: 141

Its because the Input property you are try to pass to the Test Component is "person.name", which isn't defined on your Test component. Your Test component expects something named "person". Secondly you are passing a string and not a Person type you defined on the Test Component. Change the Test component to accept a string or pass the Person and reference the name property in the Test component. And make sure the names match.

Here is two ways you can think about passing the person's name to the other component

<app-test [name]="person.name" [person]="person"></app-test>

Then in the Test Component:

 export class TestComponent  {
  @Input() name: string;
  @Input() person : Person;
}

Notice how the names and types match? My advice would be dont pass more than you need. If you just need the Person name passed, just have your component accept a string. No need to pass the whole object.

TestComponent Template:

<h1>Person: {{person.name}}</h1>
<h1>Name: {{name}}</h1>

I am going to add a link to the Angular Documentation as I think its a pretty important part of Angular you might want to review. The Heroes tutorial they have is really good.

https://angular.io/api/core/Input

Upvotes: 1

Eliseo
Eliseo

Reputation: 57909

You're correct [ngStyle] is different and [style] is different, You need

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

Other options are

<app-test [person]="person"</app-test>

And in your main.app

this.person.name='Jack'

Remember that, if you use an object in a input any change of a property of the object in parent or in child change the "properties" of the object

Upvotes: 1

Akhil
Akhil

Reputation: 1453

You can't bind to person.name, because the Input() decorator is bound to the person in the child component (test), not any specific property like person.name

You have to send an object instead to fix this issue.

See this example.

Upvotes: 2

Related Questions