Now.js Framework Documentation
Scope Isolation - Data Context Separation
Scope Isolation - Data Context Separation
Overview
To prevent conflicts when multiple systems try to process the same data-* directives, Now.js uses a Scope Isolation system.
Problem Solved
When multiple systems work with data-attr, data-text, etc. simultaneously:
<!-- ❌ Problem: Both AppConfigManager and FormManager try to process data-attr="value:company" -->
<form data-load-api="/api/user/profile">
<input name="company" data-attr="value:company">
<!-- AppConfigManager: company = "Global Company" from config API -->
<!-- FormManager: company = "User Company" from user profile API -->
<!-- Result: Unpredictable value, depends on which system runs last -->
</form>Solution: Automatic Scope Isolation
1. AppConfigManager Skips Elements in Isolated Scopes
AppConfigManager will NOT process data-* directives inside:
✅ [data-component="api"] - ApiComponent
<div data-component="api" data-api-url="/api/products">
<span data-text="name">Product Name</span>
<!-- AppConfigManager won't touch this element -->
<!-- ApiComponent manages it -->
</div>✅ form[data-load-api] - FormManager with API Loading
<form data-load-api="/api/user/profile">
<input name="company" data-attr="value:company">
<!-- AppConfigManager won't touch this element -->
<!-- FormManager manages it -->
</form>✅ [data-load-api] - Any Container with API Loading
<div data-load-api="/api/dashboard/stats">
<span data-text="totalUsers">Loading...</span>
<!-- AppConfigManager won't touch this element -->
<!-- Container manages its own data loading -->
</div>2. AppConfigManager Only Processes Global Elements
<!-- ✅ AppConfigManager WILL process these -->
<header>
<span data-text="company">My Company</span>
<img data-attr="src:logo" alt="Logo">
</header>
<footer>
<p data-text="copyright"></p>
<span data-text="version"></span>
</footer>Usage Guidelines
1. Global Configuration Data (AppConfigManager)
Use for data shared across the entire application:
<nav>
<div class="brand">
<img data-attr="src:logo" alt="Logo">
<span data-text="company">Company Name</span>
</div>
</nav>
<footer>
<p data-text="copyright">© 2024 Company</p>
</footer>// API: /api/config
{
"company": "My Company Ltd.",
"logo": "/images/logo.png",
"copyright": "© 2024 My Company Ltd.",
"variables": {
"--color-primary": "#29336b"
}
}2. Form-Specific Data (FormManager)
Use for form-specific data:
<form data-load-api="/api/user/profile">
<input type="text" name="name" data-attr="value:name">
<input type="email" name="email" data-attr="value:email">
<select name="company_id" data-attr="value:company_id">
<!-- Options loaded from data-options-api -->
</select>
</form>// API: /api/user/profile
{
"data": {
"name": "John Doe",
"email": "john@example.com",
"company_id": "123"
}
}3. Component-Specific Data (ApiComponent)
Use for components that load their own data:
<div data-component="api" data-api-url="/api/products">
<div data-for="item in items">
<h3 data-text="item.name">Product</h3>
<p data-text="item.price">Price</p>
</div>
</div>Best Practices
✅ Correct
<!-- Global config uses AppConfigManager -->
<header>
<span data-text="siteName">Site Name</span>
</header>
<!-- Form data uses FormManager -->
<form data-load-api="/api/user/profile">
<input name="username" data-attr="value:username">
</form>❌ Avoid
<!-- Don't use the same name in global and form scope -->
<header>
<span data-text="name">Global Name</span>
</header>
<form data-load-api="/api/user">
<input name="name" data-attr="value:name">
<!-- Confusing: which API does "name" come from? -->
</form>Debug Mode
Enable debug to see which elements are skipped:
Now.config.debug = true;Console will show:
[AppConfigManager] Skipped 5 elements in isolated scopes: [input, input, select, ...]Checking Scope
Use helper method to check if an element is in isolated scope:
const element = document.querySelector('input[name="company"]');
const isIsolated = AppConfigManager.isInIsolatedScope(element);
console.log(isIsolated);
// true = inside form[data-load-api] or [data-component="api"]
// false = AppConfigManager will processSummary
| Scope | Attribute | Managed By | Use Case |
|---|---|---|---|
| Global | None | AppConfigManager |
Data shared across the app |
| Form | form[data-load-api] |
FormManager |
Form-specific data |
| Component | [data-component="api"] |
ApiComponent |
Component that loads its own data |
| Container | [data-load-api] |
Custom | Container that loads its own data |
Principle: Each scope manages its own data without interfering with others