-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Answer:1 #778
Answer:1 #778
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @chekit,
thank you so much for your PR. 🙏🏻
This is the first review, I do.
So please do not take my comments too serious.
Here are general thoughts about the given goal “. The goal of the challenge is to create a CardComponent
that can be customized without any modifications.”
- I think the typing of the
list-input
ofCardComponent
would cause an issue, since the typing limits the usage to objects havingid, firstname, name
. - Other than that, I think the intention was to make the card reusable by using
ngTemplateOutlet
- Nevertheless, you managed to make the card reusable by abstracting the data-model.
- In the end, I think
ngTemplateOutlet
makes the card more reusable.
Btw:
I am not sure if I should approve the PR or not.
Not sure about the process, here. :-) //cc @tomalaforge
Cheers from Leipzig, Germany
Gregor
template: 'TODO City', | ||
template: ` | ||
<app-card | ||
[list]="data$ | async" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool that you use a stream here.
You should be able to use ChangeDetectionStrategy.OnPush
here.
#performance
#no-blocker
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely make sense 👍🏻
template: ` | ||
<app-card | ||
[list]="data$ | async" | ||
(addNewItem)="onAddNewItem()" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of onAddNewItem
you could be more specific about the handler → addNewCitiy()
.
#personalPerference
#no-blocker
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, as you noticed later the intention was to move all repetitive code out of components, to make it possible to handle it in one place.
[list]="data$ | async" | ||
(addNewItem)="onAddNewItem()" | ||
(deleteItem)="onDeleteItem($event)" | ||
[backgroundColor]="'rgba(250, 10, 250, 0.1)'"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is better than using ::ng-deep
.
We could also think of allowing to pass a class-name: backgroundClass="bg-red-200"
This allows to reuse styles from an existing CSS-Framework like prime flex or tailwind.
#idea
#no-blocker
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've left it with style
, but with refactored implementation class could be easily implemented as well :)
|
||
this.store.teachers$.subscribe((t) => (this.teachers = t)); | ||
override onAddNewItem() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, now I understand the “generic” naming.
From my experience, this adds another layer of indirection that does not provide a benefit for the developer.
This approach makes absolute sense to me if we are in the area of spinning up components dynamically from a configuration. Then we need to introduce contracts and hooks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea is to move all repeated functionality to abstract class (DRY), thus you don't need to copy paste it once you create a new card type component and focus only on the things that differs this component from others.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea is to move all repeated functionality to abstract class (DRY), thus you don't need to copy paste it once you create a new card type component and focus only on the things that differs this component from others.
Yes, I understand the goal. As far as I can tell, this approach only works in very few situations.
Often we tend to abstract too early. Then a business requirement changes, and we start adding conditions to our abstractions in order to make them work for a specific case.
That's why I value SRP (Single Responsibility Principle) over DRY.
In our challenge here, I would ask, what is a card responsible for? Aha, providing a visual boundary and a spot to render
any content.
Add | ||
</button> | ||
</div> | ||
`, | ||
styles: ` | ||
.card__image { | ||
width: 200px; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to hard-code the width of the image here, if our goal is to have an abstract card-implementation?
#api
#no-blocker
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, put this back to the specific card as it was initially.
src="assets/img/student.webp" | ||
width="200px" /> | ||
|
||
[bgColor]="backgroundColor()"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we allow passing a CSS-class, we do not need the custom BgColorDirective
.
#no-blocker
#less-code-to-maintain
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, now I see what you mean. It is definitely look like an overhead.
@Input() list: any[] | null = null; | ||
@Input() type!: CardType; | ||
@Input() customClass = ''; | ||
list = input<{ id: number; firstName?: string; name?: string }[] | null>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This typing limits the data structure we can pass to the card.
How would we act if we would like to use this card for displaying a Product
having no firstname
.
Maybe it is possible to make CardComponent
generic: CardComponent<T>
#api
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right. With the ngTemplateOutlet approach it is not need to be too specific for list property.
…dundant directive
Hi @GregOnNet, Thank you a lot for such a detailed review. It was really nice to practice and recall the concepts which I'm not using everyday. I did some changes and left a comments to your comments. Once again, much appreciation :) P.S. Cheers from Amsterdam, The Netherlands. Anton 😉 |
@chekit Hey, thanks for the feedback. I really appreciate it. Yes, I learned, that these PRs are tagged in order to mark them as answer. :-) |
This pull request is stale because it has been open for 15 days with no activity. |
This pull request was closed because it has been inactive for 5 days since being marked as stale. |
Checklist for challenge submission
Warning:
Alternatively, you can still submit your PR to join the list of answered challenges or to be reviewed by a community member. 🔥