Implementing a Custom ngClass Directive in Angular
This challenge asks you to create a custom Angular directive that mimics the functionality of the built-in ngClass directive, but with added flexibility. The goal is to understand how directives work and how to dynamically apply CSS classes to elements based on expressions. This is a fundamental skill for building dynamic and responsive Angular applications.
Problem Description
You need to create an Angular directive called CustomNgClass that allows you to conditionally apply CSS classes to an element. The directive will accept an input property named classes which will be an object where keys are CSS class names and values are boolean expressions. If the expression evaluates to true, the corresponding class will be added to the element; otherwise, it will be removed.
Key Requirements:
- The directive must be named
CustomNgClass. - It must accept an input property named
classesof type{ [className: string]: any }. - The directive must dynamically add or remove CSS classes from the host element based on the boolean values associated with each class name in the
classesinput. - The directive should handle cases where the
classesinput is null or undefined gracefully (no errors, no classes applied). - The directive should re-evaluate the expressions whenever the input
classesobject changes.
Expected Behavior:
When the classes input changes, the directive should update the element's class list accordingly. If a class's expression evaluates to true, the class should be present on the element. If it evaluates to false, the class should be removed.
Edge Cases to Consider:
classesinput isnullorundefined.- Expressions in the
classesobject evaluate to unexpected values (e.g., non-boolean values). While the directive doesn't need to handle non-boolean values explicitly (Angular will handle the type coercion), be aware of this potential behavior. - The directive should not throw errors if a class name is invalid.
- Performance: While not a primary concern for this exercise, consider how the directive will perform with a large number of classes.
Examples
Example 1:
Input:
<div [customNgClass]="{ 'highlight': isHighlighted, 'bold-text': isBold }">
This is some text.
</div>
where:
isHighlighted = true
isBold = false
Output:
<div class="highlight">This is some text.</div>
Explanation: The highlight class is applied because isHighlighted is true, while bold-text is not applied because isBold is false.
Example 2:
Input:
<div [customNgClass]="{ 'error': hasError, 'success': isSuccess }">
Status:
</div>
where:
hasError = false
isSuccess = true
Output:
<div class="success">Status:</div>
Explanation: The success class is applied because isSuccess is true, and the error class is not applied because hasError is false.
Example 3:
Input:
<div [customNgClass]="classes">
Content
</div>
where:
classes = {
'active': isActive,
'disabled': isDisabled,
'special': isSpecial
}
and:
isActive = false
isDisabled = true
isSpecial = false
Output:
<div class="disabled">Content</div>
Explanation: Only the disabled class is applied because only isDisabled is true.
Constraints
- The directive must be written in TypeScript.
- The directive must be compatible with a standard Angular project setup (no external libraries beyond Angular itself).
- The expressions in the
classesobject should be evaluated using Angular's change detection mechanism. - The directive should not modify the element's class list directly, but rather use Angular's built-in mechanisms for class binding.
Notes
- Consider using
ngOnChangeslifecycle hook to detect changes in theclassesinput. - Remember that the values in the
classesobject are expressions that will be evaluated in the context of the component. - Think about how to handle potential errors or unexpected values in the expressions. While explicit error handling isn't required, be mindful of potential issues.
- Focus on the core functionality of conditionally applying classes based on expressions. Advanced features like class precedence or complex conditional logic are not required for this challenge.