Skip to content

Commit

Permalink
feat: RemoteFormController - Controller for handling UJS remote form …
Browse files Browse the repository at this point in the history
…responses
  • Loading branch information
Sub-Xaero committed Mar 9, 2021
1 parent b9c8986 commit fdf0e5f
Show file tree
Hide file tree
Showing 18 changed files with 129 additions and 9 deletions.
1 change: 1 addition & 0 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export { LimitedSelectionCheckboxesController } from "./limited_selection_checkb
export { NestedFormController } from "./nested_form_controller";
export { PasswordConfirmController } from "./password_confirm_controller";
export { PasswordPeekController } from "./password_peek_controller";
export { RemoteFormController } from "./remote_form_controller";
export { ResponsiveIframeBodyController, ResponsiveIframeWrapperController } from "./responsive_iframe_controller";
export { ScrollIntoFocusController } from "./scroll_into_focus_controller";
export { ScrollToBottomController } from "./scroll_to_bottom_controller";
Expand Down
2 changes: 1 addition & 1 deletion dist/index.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions dist/remote_form_controller.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { BaseController } from "./base_controller";
export declare class RemoteFormController extends BaseController {
static targets: never[];
static values: {
selector: StringConstructor;
};
readonly hasSelectorValue: boolean;
readonly selectorValue: string;
get selector(): string;
replace(event: {
detail: [Element, any, XMLHttpRequest];
}): void;
}
//# sourceMappingURL=remote_form_controller.d.ts.map
1 change: 1 addition & 0 deletions dist/remote_form_controller.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/stimulus-library.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/stimulus-library.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/stimulus-library.modern.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/stimulus-library.modern.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/stimulus-library.module.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/stimulus-library.module.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/stimulus-library.umd.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/stimulus-library.umd.js.map

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
** [PasswordConfirmController](./controllers/password_confirm_controller.md "Stimulus Library - PasswordConfirmController")
** [PasswordPeekController](./controllers/password_peek_controller.md "Stimulus Library - PasswordPeekController")
** [ResponsiveIFrameController](controllers/responsive_iframe_controller.md "Stimulus Library - ResponsiveIFrame")
** [RemoteFormController](controllers/remote_form_controller.md "Stimulus Library - RemoteFormController")
** [ScrollIntoFocusController](./controllers/scroll_into_focus_controller.md "Stimulus Library - ScrollIntoFocusController")
** [ScrollToBottomController](./controllers/scroll_to_bottom_controller.md "Stimulus Library - ScrollToBottomController")
** [ScrollToController](./controllers/scroll_to_controller.md "Stimulus Library - ScrollToController")
Expand Down
62 changes: 62 additions & 0 deletions docs/controllers/remote_form_controller.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# RemoteFormController

## Purpose

A Stimulus controller to deal with Rails UJS remote forms and their submission responses.

<!-- tabs:start -->

## ** Actions **

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

| Action | Purpose |
| --- | --- |
| `replace` | Replace the attached form with the contents of the response. Needs to be wired up to the UJS `ajax:success` and/or `ajax:error` events. |

## ** Targets **

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

[no-targets](../_partials/no-targets.md ':include')

## ** Classes **

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

[no-classes](../_partials/no-classes.md ':include')

## ** Values **

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

| Value | Type | Description | Default |
| --- | --- | --- | --- |
| `selector` (Optional) | String | A css selector to query the response with. The selected element(s) are what the attached form will be replaced with. | The controller identifier. It looks for another form with the same controller in the response |

## ** Events **

#### Events

[no-events](../_partials/no-events.md ':include')

## ** Side Effects **

None

<!-- tabs:end -->

# How to Use

Annotate a Rails form with `data-remote: true` and add this controller. You can then send HTML responses from the server that this controller will pick up and replace the connected form element with.

<!-- tabs:start -->

## ** HTML/ERB **

[example](../examples/remote_form_controller.erb ':include :type=code')

## ** HAML **

[example](../examples/remote_form_controller.haml ':include :type=code')
<!-- tabs:end -->
4 changes: 4 additions & 0 deletions docs/examples/remote_form_controller.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<%= simple_form_for model, method: :post, remote: true, data: { controller: 'remote-form', action: 'ajax:success->remote-form#replace ajax:error->remote-form#replace' } do |f| %>
<%= f.input :name %>
<%= f.input :description %>
<% end %>
3 changes: 3 additions & 0 deletions docs/examples/remote_form_controller.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
= simple_form_for model, method: :post, remote: true, data: { controller: 'remote-form', action: 'ajax:success->remote-form#replace ajax:error->remote-form#replace' } do |f|
= f.input :name
= f.input :description
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export {LimitedSelectionCheckboxesController} from "./limited_selection_checkbox
export {NestedFormController} from "./nested_form_controller";
export {PasswordConfirmController} from "./password_confirm_controller";
export {PasswordPeekController} from "./password_peek_controller";
export {RemoteFormController} from "./remote_form_controller";
export {ResponsiveIframeBodyController, ResponsiveIframeWrapperController} from "./responsive_iframe_controller";
export {ScrollIntoFocusController} from "./scroll_into_focus_controller";
export {ScrollToBottomController} from "./scroll_to_bottom_controller";
Expand Down
33 changes: 33 additions & 0 deletions src/remote_form_controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {BaseController} from "./base_controller";

export class RemoteFormController extends BaseController {
static targets = [];

static values = {selector: String};

declare readonly hasSelectorValue: boolean;
declare readonly selectorValue: string;

get selector(): string {
return this.hasSelectorValue ? this.selectorValue : `[data-controller~="${this.identifier}"]`;
}

replace(event: { detail: [Element, any, XMLHttpRequest] }) {
const [data, status, xhr] = event.detail;
if (data instanceof Node) {
let new_element = data.querySelector(this.selector);

if (new_element == null) {
throw new Error(`expected new form DOM with [data-controller="${this.identifier}"] to be present in returned payload`);
}

let parentNode = this.el.parentNode;
if (parentNode == null) {
throw new Error('expected form to have a DOM parent, could not execute replaceChild');
}
parentNode.replaceChild(new_element, this.el);
} else {
console.log('Unknown', data);
}
}
}

0 comments on commit fdf0e5f

Please sign in to comment.