Skip to content

Commit

Permalink
feat(Controller): New SignalEnable and SignalDisable controllers whic…
Browse files Browse the repository at this point in the history
…h can enable/disable elements based on whether a value matches a given expression
  • Loading branch information
Sub-Xaero committed Sep 13, 2022
1 parent 7163747 commit 54d1757
Show file tree
Hide file tree
Showing 7 changed files with 246 additions and 10 deletions.
14 changes: 10 additions & 4 deletions docs/docs/controllers/signal/signal_action_controller.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,16 @@ the same `nameValue` as the `nameValue` of this controller.

## Events

| Event | When | Dispatched on | `event.detail` |
|--------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|------------------------------------------------------------------------------|
| `signal:match:${nameValue}` | When value of the input for `nameValue` changes, and the expression in `whenValue` evaluates to _true_ against the new updated value | The controller root element | `element`: the controller root element,<br/><br/> `value`: the changed value |
| `signal:no-match:${nameValue}` | When value of the input for `nameValue` changes, and the expression in `whenValue` evaluates to _false_ against the new updated value | The controller root element | `element`: the controller root element,<br/><br/> `value`: the changed value |
| Event | When | Dispatched on | `event.detail` | |
|--------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|----------------|---------------------------------------------------------------|
| `signal:match:${nameValue}` | When value of the input for `nameValue` changes, and the expression in `whenValue` evaluates to _true_ against the new updated value | The controller root element | | |
| | | | `element` | the controller root element |
| | | | `predicate` | the expression the controller used to try and match the value |
| | | | `value` | the value that was received |
| `signal:no-match:${nameValue}` | When value of the input for `nameValue` changes, and the expression in `whenValue` evaluates to _false_ against the new updated value | The controller root element | | |
| | | | `element` | the controller root element |
| | | | `predicate` | the expression the controller used to try and match the value |
| | | | `value` | the value that was received |


## Side Effects
Expand Down
75 changes: 75 additions & 0 deletions docs/docs/controllers/signal/signal_disable_controller.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
id: SignalDisableController
title: SignalDisableController
---


import NoTargets from "../../_partials/no-targets.md";
import NoActions from "../../_partials/no-actions.md";
import NoSideEffects from "../../_partials/no-side-effects.md";
import Expressions from "../../_partials/expressions.md";
import NoClasses from "../../_partials/no-classes.md";

## Purpose

A controller that responds to SignalInputController notifications.
This controller adds the `disabled` attribute from an element when a value-change notification evaluates to
false against the expression given in `whenValue` evaluate to true, and removes `disabled` when it evaluates to false.

This controller can be anywhere in the DOM tree and it will receive notifications from any SignalInputController with
the same `nameValue` as the `nameValue` of this controller.

### Example Use Cases
- Turn off inputs in a form when another input has a certain value, See also: SignalVisibiityController to hide elements when they are not needed.

## [Actions](https://stimulus.hotwire.dev/reference/actions)
<NoActions/>

## [Targets](https://stimulus.hotwire.dev/reference/targets)
<NoTargets/>

## [Classes](https://stimulus.hotwire.dev/reference/classes)
<NoClasses/>

## [Values](https://stimulus.hotwire.dev/reference/values)

| Value | Type | Description | Default |
|--------|--------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|
| `name` | String | The name of the input value whose value to react to. This name should be the same as the `nameValue` of the SignalInputController you want to sync with. | `-` |
| `when` | String | A simple _expression_ which will be evaluated against the value received from SignalInputController. If the expression evaluates to true, the controller will add the `disabled` attribute to the controller element, otherwise it will remove it . | `-` |

<Expressions/>


## Events

| Event | When | Dispatched on | `event.detail` | |
|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|----------------|---------------------------------------------------------------|
| `signal:disable:${nameValue}` | When value of the input for `nameValue` changes, and the expression in `whenValue` evaluates to _true_ against the new updated value | The controller root element | | |
| | | | `element` | the controller root element |
| | | | `predicate` | the expression the controller used to try and match the value |
| | | | `value` | the value that was received |
| `signal:enable:${nameValue}` | When value of the input for `nameValue` changes, and the expression in `whenValue` evaluates to _false_ against the new updated value | The controller root element | | |
| | | | `element` | the controller root element |
| | | | `predicate` | the expression the controller used to try and match the value |
| | | | `value` | the value that was received |


## Side Effects
<NoSideEffects/>

## How to Use

```html

<input type="number" name="foo" data-controller="signal-disable">

<div
data-controller="signal-disable bar"
data-signal-disable-name-value="foo"
data-signal-disable-when-value="=3 || =5"
>
<!-- the element will have the [disabled] attribute if the value of input[name="foo"] is 3 or 5 -->
</div>

```
74 changes: 74 additions & 0 deletions docs/docs/controllers/signal/signal_enable_controller.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
id: SignalEnableController
title: SignalEnableController
---

import NoTargets from "../../_partials/no-targets.md";
import NoActions from "../../_partials/no-actions.md";
import NoSideEffects from "../../_partials/no-side-effects.md";
import Expressions from "../../_partials/expressions.md";
import NoClasses from "../../_partials/no-classes.md";

## Purpose

A controller that responds to SignalInputController notifications.
This controller removes the `disabled` attribute from an element when a value-change notification evaluates to
false against the expression given in `whenValue` evaluate to true, and adds `disabled="true"` when it evaluates to false.

This controller can be anywhere in the DOM tree and it will receive notifications from any SignalInputController with
the same `nameValue` as the `nameValue` of this controller.

### Example Use Cases
- Turn off inputs in a form when another input has a certain value, See also: SignalVisibiityController to hide elements when they are not needed.

## [Actions](https://stimulus.hotwire.dev/reference/actions)
<NoActions/>

## [Targets](https://stimulus.hotwire.dev/reference/targets)
<NoTargets/>

## [Classes](https://stimulus.hotwire.dev/reference/classes)
<NoClasses/>

## [Values](https://stimulus.hotwire.dev/reference/values)

| Value | Type | Description | Default |
|--------|--------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|
| `name` | String | The name of the input value whose value to react to. This name should be the same as the `nameValue` of the SignalInputController you want to sync with. | `-` |
| `when` | String | A simple _expression_ which will be evaluated against the value received from SignalInputController. If the expression evaluates to false, the controller will add the `disabled` attribute to the controller element, otherwise it will remove it. | `-` |

<Expressions/>


## Events

| Event | When | Dispatched on | `event.detail` | |
|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|----------------|---------------------------------------------------------------|
| `signal:enable:${nameValue}` | When value of the input for `nameValue` changes, and the expression in `whenValue` evaluates to _true_ against the new updated value | The controller root element | | |
| | | | `element` | the controller root element |
| | | | `predicate` | the expression the controller used to try and match the value |
| | | | `value` | the value that was received |
| `signal:disable:${nameValue}` | When value of the input for `nameValue` changes, and the expression in `whenValue` evaluates to _false_ against the new updated value | The controller root element | | |
| | | | `element` | the controller root element |
| | | | `predicate` | the expression the controller used to try and match the value |
| | | | `value` | the value that was received |


## Side Effects
<NoSideEffects/>

## How to Use

```html

<input type="number" name="foo" data-controller="signal-enable">

<div
data-controller="signal-enable bar"
data-signal-enable-name-value="foo"
data-signal-enable-when-value="=3 || =5"
>
<!-- the element will have the [disabled] attribute unless the value of input[name="foo"] is 3 or 5 -->
</div>

```
5 changes: 0 additions & 5 deletions src/controllers/signal/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,3 @@ export function signalConnectEvent(name: string): string {
export function signalValueEvent(name: string): string {
return signalEventName(name, 'value');
}

export function signalVisibilityEvent(name: string, action: "hide" | "show"): string {
return signalEventName(`${name}:${action}`, 'visibility');
}

4 changes: 3 additions & 1 deletion src/controllers/signal/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export * from './signal_action_controller';
export * from './signal_disable_controller';
export * from './signal_dom_children_controller';
export * from './signal_enable_controller';
export * from './signal_input_controller';
export * from './signal_visibility_controller';
export * from './signal_visibility_controller';
42 changes: 42 additions & 0 deletions src/controllers/signal/signal_disable_controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {SignalPayload} from "src/*";
import {signalEnableDisableEvent, signalEventName} from "./events";
import {SignalBaseController} from "./base_controller";

export class SignalDisableController extends SignalBaseController {

static values = {
name: String,
when: String,
};

declare nameValue: string;
declare whenValue: string;

disable() {
this.el.setAttribute("disabled", "true");
}

enable() {
this.el.removeAttribute("disabled");
}

_onSignal(payload: SignalPayload) {
let value = payload.value;
if (this.whenValue == "default") {
if (value == "") {
this.disable();
} else {
this.enable();
}
return;
}
if (this.allPredicatesMatch(value)) {
this.dispatchEvent(this.el, signalEventName(this.nameValue, "disable"), {detail: {predicate: this.whenValue, value}});
this.disable();
} else {
this.dispatchEvent(this.el, signalEventName(this.nameValue, "enable"), {detail: {predicate: this.whenValue, value}});
this.enable();
}
}

}
42 changes: 42 additions & 0 deletions src/controllers/signal/signal_enable_controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {SignalPayload} from "src/*";
import {signalEventName} from "./events";
import {SignalBaseController} from "./base_controller";

export class SignalEnableController extends SignalBaseController {

static values = {
name: String,
when: String,
};

declare nameValue: string;
declare whenValue: string;

disable() {
this.el.setAttribute("disabled", "true");
}

enable() {
this.el.removeAttribute("disabled");
}

_onSignal(payload: SignalPayload) {
let value = payload.value;
if (this.whenValue == "default") {
if (value == "") {
this.enable();
} else {
this.disable();
}
return;
}
if (this.allPredicatesMatch(value)) {
this.dispatchEvent(this.el, signalEventName(this.nameValue, "enable"), {detail: {predicate: this.whenValue, value}});
this.enable();
} else {
this.dispatchEvent(this.el, signalEventName(this.nameValue, "disable"), {detail: {predicate: this.whenValue, value}});
this.disable();
}
}

}

0 comments on commit 54d1757

Please sign in to comment.