Model-View-Presenter with Angular

Hi there!

Feel free to send me any questions about Model-View-Presenter with Angular, the article or the pattern.

3 Likes

Hello Lars! Awesome article!

I would like to know your opinion on where complex logic should go within this pattern. From your article i understand that:

  • container components: are responsible for fetching data from service and passing that (with suitable shape) to a presentational component

  • presentational component: (or dumb component) is responsible of displaying the view and if needed passing down data to a presenter.

  • presenter: is in charge of complex business logic. In this type of service i would do all business logic related so that the presentational component displays the view correctly

Example
Lets say we have a product card component that displays product data on the screen.

An occasional discount on a product, like a coupon, will be applied, component API would be:
@Input product: Product
@Input coupon: string

Presenter logic would be:

  1. Apply coupon discount to product price
  2. Calculate percentage discount to display on the product card as a label
  3. If percentage discount is bigger than 10% show percentage discount label in a different color.

My question is:
How would a presentational component with multiple inputs (@Input) pass those inputs to a presentar so that the presenter can execute complex logic on them, knowing that inputs have no specific order when bindings occurs. Even if there was a specific order, how would you wait for all inputs to have non-null values to call complexLogic() on the presenter?

How do you synchronize the 2 inputs to invoque the presenter correctly?

Thank you!

1 Like

Thank you for posting your question in inDepth Community, Mauricio!

The app would have to send the coupon code to the server to calculate a discount, right?

Hi Lars, yes it would have to send it to the server. The purpose of the example is to have a component with more than 1 input and logic on a presenter depending on these inputs.

If it helps, i can try to think about another example that serves the purpose.

Thanks.

Server communication is a job for a container component or even better a service which the container component forwards control to.

Maybe we can change the example to a percentage being passed to the presentational slide component?

1 Like

Hi Lars

I have question relating container and presentational components

Question 1)
Can a container have in its template another container ?

Question 2)
Can a presentational component have in its template a container ?

Agree. Yes, a percentage being passed to the presentational component is ok. As long as there are 2 Inputs on which a logic depends on, i think it serves the purpose.

Hey Dhaval,

You can have other templates in a presentational component’s template (if that’s the question you’re asking), but these templates need to also be dump components. So the presentational component can pass data into them (using @Input()) and the presentational component can listen for outputs from these templates.

I think it’s best to avoid having presentational components inside other presentational components. It makes it hard to keep track of the flow of data through the app.

Hope that helps.

Stephen

Great overview of the MVP pattern Lars.

1 Like

Thanks Stephen. I guess the question I was asking was

  1. in a container template, can you have another conatiner component as its ViewChild?
  2. In a presenter template , can you have another conatiner component as its ViewChild ?

If we have a component whose responsibility it is to simply compose container components, this is a presentational component. It has nothing to do with state, it simply orders other components to lay out a piece of a page.

We can also put container components in content children and templates that we pass to a presentational component.

Container components shouldn’t take state from parent components.

The main thing is to not have mixed components. Components should either have presentational concerns or glue the presentation layer to the rest of our app using services and other kinds of dependencies.

These answers might not be final. Try to convince me otherwise and I will be happy to discuss.

2 Likes

Hi @mauricio ,

Here’s a StackBlitz workspace demonstrating your example with some sample data.

Input properties are marked as optional (can be undefined). If you want them to support null, you would have to reflect that in their types.

Getters on the component model forwards input properties to the presenter to delegate computation of the UI properties.

The presenter accepts optional parameters and use default bottom values instead.

The component template binds to the UI properties of the component model (the getters) and apply formatting using pipes.

The color of the sale label is controlled through the conditional addition of a state CSS class which is bound to a UI property.

3 Likes

This is awesome, thank you for taking the time for doing this, it is a great example.

I added a new attribute “specialDiscount” that is independent of Items, what im trying to see with this example is how MVP would work when the presenter receives inputs that are not synced.

In this example you will see how after 5 seconds (simulating an http request to an independent service) the product card changes. This is trying to simulate if the user is elegible for a special deal and you would get that from a different service than the one you use for getting Items.

Im tyring to identify the proper way of using the pattern but also how not to use it.

I know this is not a great example and one would solve it using a different approach, like combineLatest but maybe there are cases where this is still applicable.

Again, thank you @LayZee !

Note: Please check “// NEW INDEPENDENT FIELD SIMULATING DELAY WITH items$” comment on carousel.container.ts

Which product is the special discount for? We are outside the scope of Model-View-Presenter now. The container component just needs to call an Angular service. The service figures out the business logic. MVP ends at the container components.