0

I am trying to set the width and height of a component alongside its initial declaration in a parent component's html. Having the following component tag (in the parent's html):

<app-ipe-artboard [artboard]="artboard" [ngStyle]="setStyle()"></app-ipe-artboard>

Where setStyle() is a method on the artboard component (itself):

@Component({
    selector: 'app-ipe-artboard'
})
export class ArtboardComponent implements OnInit {
    @Input() public artboard: Artboard;

    ngOnInit() {
    }

    setStyle(): object {
        return {
            width: this.artboard.width + 'px',
            height: this.artboard.height + 'px'
        };
    }
}

Is it possible to reach this method (not in the way I have put it now because it gives compile time error and undesired runtime behavior consecutively)? Or is the component not yet instantiated when it is rendered at this this place and does this need to be done somehow different?

Youp Bernoulli
  • 5,303
  • 5
  • 39
  • 59

1 Answers1

1

The issue is that right now the parent component is looking for it's own setStyle method and not finding any, so it throws a runtime error. The methods on the app-ipe-artboard are scoped to that component and cannot be reached by the parent (unless you pass a reference to that component to your parent component, which doesn't do much to clean this up).

Solution 1

Assuming the behavior you are looking for is to set the width and height of the child component based on variables on the artboard, you can accomplish this with @HostBinding.

@Component({
  selector: 'app-ipe-artboard'
})
export class ArtboardComponent implements OnInit {
    @Input() public artboard: Artboard;
    @HostBinding('style.width') artboardWidth;
    @HostBinding('style.height') artboardHeight;

    ngOnInit() {
      this.artboardWidth = artboard.width;
      this.artboardHeight = artboard.height;
    }
}

Solution 2

Another way you can do this, since you have the artboard in the parent, is just move that setStyle method to the parent component.

parent component

@Component({
  template: `<app-ipe-artboard [artboard]="artboard" [ngStyle]="setStyle()"></app-ipe-artboard>`
})
export class ParentComponent {
  artboard: Artboard = {width: 500, height: 300};

  setStyle() {
    return { width: this.artboard.width + 'px', height: this.artboard.height + 'px' }
  }
}

Solution 3
From Gunter's answer here.

You need to pass the same value you would add to an element like and sanitize the styles.

Sample code provided by Gunter:

@HostBinding('style')
get myStyle(): String {
  return this.sanitizer.bypassSecurityTrustStyle('background: red; display: block;');
}

constructor(private sanitizer:DomSanitizer) {}
vince
  • 7,808
  • 3
  • 34
  • 41
  • Thanks for providing two ways of doing this. I tend to prefer the first one to keep it the component's responsibility itself. Does this approach also keep an active databinding between artboardWidth & artboard.width as in: when the component is resized by a user it is reflected in the accompanying business object? That would then be most beneficial. – Youp Bernoulli Feb 14 '18 at 09:48
  • Actually when imlementing it gave this error: [Angular] Can't bind to 'width' since it isn't a known property of 'app-ipe-artboard'. 1. If 'app-ipe-artboard' is an Angular component and it has 'width' input, then verify that it is part of this module. 2. If 'app-ipe-artboard' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message. 3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component. – Youp Bernoulli Feb 14 '18 at 10:14
  • Have you declared the AppIpeArtboardComponent (or whatever the class name is for that component) in your module? – vince Feb 14 '18 at 14:32
  • Are you sure it's the correct module? Unfortunately that error is unrelated to the actual question and I can't see the relevant code. Double check your module declarations and try troubleshooting. Maybe open a separate question? – vince Feb 20 '18 at 15:49
  • I thought about it last night and I think it should be @HostBinding('style.width'), width itself is not a property of a web component I guess...what do you think? – Youp Bernoulli Feb 21 '18 at 08:39
  • Ah yes, it is `style.width` and probably `style.width.px` if you just want to use a number for the property and know your unit is always pixels. Fixed my answer. That's separate from the error about `app-ipe-artboard` not being an Angular component however. – vince Feb 21 '18 at 14:41
  • 1
    Marked as answer now... the final solution I chose is to bind to style (in general) based upon this: https://stackoverflow.com/a/46151691/468910 – Youp Bernoulli Feb 21 '18 at 14:53
  • That's a nice solution, I'll add it to my answer to cover all the bases. – vince Feb 21 '18 at 15:58