mirror of
https://github.com/django-components/django-components.git
synced 2025-08-09 00:37:59 +00:00
feat: add self
context var and make is_filled
into attribute (#632)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
2d0f270df4
commit
e712800f5e
5 changed files with 265 additions and 31 deletions
|
@ -65,7 +65,7 @@ from django_components.slots import (
|
|||
)
|
||||
from django_components.utils import gen_id, validate_typed_dict, validate_typed_tuple
|
||||
|
||||
# TODO_DEPRECATE_V1 - REMOVE IN V1, users should use top-level import instead
|
||||
# TODO_REMOVE_IN_V1 - Users should use top-level import instead
|
||||
# isort: off
|
||||
from django_components.component_registry import AlreadyRegistered as AlreadyRegistered # NOQA
|
||||
from django_components.component_registry import ComponentRegistry as ComponentRegistry # NOQA
|
||||
|
@ -94,6 +94,12 @@ class RenderInput(Generic[ArgsType, KwargsType, SlotsType]):
|
|||
escape_slots_content: bool
|
||||
|
||||
|
||||
@dataclass()
|
||||
class RenderStackItem(Generic[ArgsType, KwargsType, SlotsType]):
|
||||
input: RenderInput[ArgsType, KwargsType, SlotsType]
|
||||
is_filled: Optional[Dict[str, bool]]
|
||||
|
||||
|
||||
class ViewFn(Protocol):
|
||||
def __call__(self, request: HttpRequest, *args: Any, **kwargs: Any) -> Any: ... # noqa: E704
|
||||
|
||||
|
@ -219,7 +225,7 @@ class Component(Generic[ArgsType, KwargsType, DataType, SlotsType], metaclass=Co
|
|||
self.fill_content = fill_content or {}
|
||||
self.component_id = component_id or gen_id()
|
||||
self.registry = registry or registry_
|
||||
self._render_stack: Deque[RenderInput[ArgsType, KwargsType, SlotsType]] = deque()
|
||||
self._render_stack: Deque[RenderStackItem[ArgsType, KwargsType, SlotsType]] = deque()
|
||||
# None == uninitialized, False == No types, Tuple == types
|
||||
self._types: Optional[Union[Tuple[Any, Any, Any, Any], Literal[False]]] = None
|
||||
|
||||
|
@ -241,7 +247,29 @@ class Component(Generic[ArgsType, KwargsType, DataType, SlotsType], metaclass=Co
|
|||
|
||||
# NOTE: Input is managed as a stack, so if `render` is called within another `render`,
|
||||
# the propertes below will return only the inner-most state.
|
||||
return self._render_stack[-1]
|
||||
return self._render_stack[-1].input
|
||||
|
||||
@property
|
||||
def is_filled(self) -> Dict[str, bool]:
|
||||
"""
|
||||
Dictionary describing which slots have or have not been filled.
|
||||
|
||||
This attribute is available for use only within the template as `{{ component_vars.is_filled.slot_name }}`,
|
||||
and within `on_render_before` and `on_render_after` hooks.
|
||||
"""
|
||||
if not len(self._render_stack):
|
||||
raise RuntimeError(
|
||||
f"{self.name}: Tried to access Component's `is_filled` attribute "
|
||||
"while outside of rendering execution"
|
||||
)
|
||||
|
||||
ctx = self._render_stack[-1]
|
||||
if ctx.is_filled is None:
|
||||
raise RuntimeError(
|
||||
f"{self.name}: Tried to access Component's `is_filled` attribute " "before slots were resolved"
|
||||
)
|
||||
|
||||
return ctx.is_filled
|
||||
|
||||
def get_context_data(self, *args: Any, **kwargs: Any) -> DataType:
|
||||
return cast(DataType, {})
|
||||
|
@ -508,13 +536,16 @@ class Component(Generic[ArgsType, KwargsType, DataType, SlotsType], metaclass=Co
|
|||
# to access the provided context, slots, etc. Also required so users can
|
||||
# call `self.inject()` from within `get_context_data()`.
|
||||
self._render_stack.append(
|
||||
RenderInput(
|
||||
context=context,
|
||||
slots=slots,
|
||||
args=args,
|
||||
kwargs=kwargs,
|
||||
escape_slots_content=escape_slots_content,
|
||||
)
|
||||
RenderStackItem(
|
||||
input=RenderInput(
|
||||
context=context,
|
||||
slots=slots,
|
||||
args=args,
|
||||
kwargs=kwargs,
|
||||
escape_slots_content=escape_slots_content,
|
||||
),
|
||||
is_filled=None,
|
||||
),
|
||||
)
|
||||
|
||||
self._validate_inputs()
|
||||
|
@ -557,6 +588,7 @@ class Component(Generic[ArgsType, KwargsType, DataType, SlotsType], metaclass=Co
|
|||
# to see if given slot was filled, e.g.:
|
||||
# `{% if variable > 8 and component_vars.is_filled.header %}`
|
||||
slot_bools = {slot_fill.escaped_name: slot_fill.is_filled for slot_fill in resolved_fills.values()}
|
||||
self._render_stack[-1].is_filled = slot_bools
|
||||
|
||||
with context.update(
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue