1

I have a dumb angular component which takes @input from it's parent. Currently this component has 4 input properties and i need to add one more.

Should I add the 5th input property or should i create a config object and pass as @input. What should be the best practice?

Mahesh
  • 325
  • 1
  • 2
  • 11
  • I found this post where some of the problems of passing config object are mentioned. https://stackoverflow.com/questions/47743281/refactoring-angular-components-from-many-inputs-outputs-to-a-single-config-objec/53456291#53456291 – Mahesh Jan 17 '19 at 17:00
  • use @Input for each field as much as possible, thus you can leverage existing change detection provided by ngOnChanges. That is to say, do not group them into an object if not necessary. – ABOS Jan 17 '19 at 18:53
  • @ABOS that's a different story about immutable objects. he can as well use `Object.assign({}, prevObj, someProp: newPropValue)` or es6 object spread and change detection would pick it up. on the other hand, having "as much as possible" `@Input`s might cause additional renders that are not necessary. – dee zg Jan 17 '19 at 21:00
  • if you pass an object as @Input and mutate its field content, ngOnChanges won't pick it up. You have to use more complex ngDoCheck. For OnPush, it is another story. – ABOS Jan 17 '19 at 21:05

3 Answers3

1

One option would be putting the state into a Service and using it to update the component. Services are a great way to extract logic from other parts of the app and have it in central locations. So instead of using inputs, you just declare the variables in your component, then whenever you need to pass the data to the component you just call a method in the service that emits the inputs, (whose state is taken care of in the service) you need. In the component's constructor you pass it in as a private parameter (the private part is very important). Implement OnInit from angular/core and subscribe to the method, and in the subscription you use a function to update the variables. If you see yourself using the inputs elsewhere you might want to create a data object as well as passing one object is much easier than passing in multiple variables.

Component Pseudocode:

@Component(... some stuff here ...)
export class YourComponent implements OnInit{ //don't forget to import OnInit
vars: varTypes;

constructor(private yourComponentService YourComponentService) {}
ngOnInit(){
    this.yourComponentService.getVars.subscribe((vars)=>this.vars = vars);
}

Service Pseudocode:

@Injectable({ 
    providedIn: 'root'
})
export class YourComponentService {
  gettingVars = new EventEmitter<varTypes>();
  private vars: varTypes = x;

  public getVars() {
    this.gettingVars.emit(vars);
  }

  public setVars(vars: varTypes) {
     this.vars = vars;
     getVars();
  }
}
SmartLeif
  • 11
  • 3
  • 1
    isn't this a huge overkill and anti-pattern for direct parent-child communication? of course its good for siblings or components no very different places in components tree, but for parent-child...? – dee zg Jan 17 '19 at 17:14
  • It might be an anti-pattern for direct parent-child communication, that's right. If the app is a simple one I actually wouldn't recommend this because simply using inputs could be easier to implement. It does, however make it easier to manage state across a larger application. Definitely consider if this is overkill before implementing. – SmartLeif Jan 17 '19 at 17:29
  • I think it would not be good practice to inject a data service in a dumb component. – Mahesh Jan 18 '19 at 05:29
  • It being a dumb component doesn't determine where else the values are used. It could be a dumb component that simply displays its values, but its values could be used everywhere else in the app, in which case it would be a great idea to use a service. – SmartLeif Jan 23 '19 at 00:13
0

It depends on what your data is and how is it related. Its pretty much not an angular question but about data modeling.

In general, group together data that makes sense together.

For example, if you have child that needs firstName, lastName, address, age for some person, it wouldn't make sense to send 4 @Inputs. You would rather create new type Person with those 4 properties and send whole Person as a single @Input.

Now, if same component needs totalNumberOfPersons, it wouldn't make too much sense to pack that int into Person type but you would be sending that one as a separate @Input; so you would end up with 2 @Inputs:

@Input()
person: Person

@Input()
totalNumberOfPersons: int
dee zg
  • 13,793
  • 10
  • 42
  • 82
0

just add it and be done with it. 5 input properties is not a lot.

  • 1
    This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. - [From Review](/review/low-quality-posts/21960600) – zgue Jan 17 '19 at 21:31
  • @zgue darn, I just realized that I left an answer. I was in a rush and did not leave a comment. sorry about that. – Michael Henderson Jan 18 '19 at 13:48