Introducing Wire for Drupal, the Livewire concepts adapted to work with Drupal

hugronaphor 19 views 42 slides Jun 06, 2024
Slide 1
Slide 1 of 42
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27
Slide 28
28
Slide 29
29
Slide 30
30
Slide 31
31
Slide 32
32
Slide 33
33
Slide 34
34
Slide 35
35
Slide 36
36
Slide 37
37
Slide 38
38
Slide 39
39
Slide 40
40
Slide 41
41
Slide 42
42

About This Presentation

Wire docs: https://wire-drupal.com/docs/quickstart

Presentation recording: https://www.youtube.com/watch?v=rJRohjxBnSo

As a user of both Laravel and Drupal, I was dreaming of having something similar to Livewire in the Drupal ecosystem. One day, I sat down to reverse-engineer it and realized that ...


Slide Content

Cornel Andreev / cornel.co Bringing Livewire to Drupal Component-based dynamic interfaces twitter.com/hugronaphor drupal.org/u/hugronaphor linkedin.com/in/cornelandreev

Prelude

The £ has fallen sharply against everything

Performance chart

namespace Drupal\hello_ajax\Controller ; use Drupal\Core\Controller\ControllerBase ; use Drupal\Core\Render\RendererInterface ; use Symfony\Component\DependencyInjection\ContainerInterface ; use Symfony\Component\HttpFoundation\JsonResponse ; /** * Json response for Ajax route. */ class HelloAjaxController extends ControllerBase { protected ?RendererInterface $renderer ; public function __construct (RendererInterface $renderer ) { $this -> renderer = $renderer ; } public static function create (ContainerInterface $container ) { return new static ( $container -> get ( 'renderer' ) ) ; } public function createHelloAjaxResponse (): JsonResponse { $time = [ '#markup' => $this -> t ( 'My items: @items' , [ '@items' => '...' , ]) , ] ; $response [ 'items' ] = $this -> renderer -> render ( $time ) ; return new JsonResponse( $response ) ; } } ( function ($ , Drupal) { 'use strict'; /** * Replaces content response from Ajax call. */ Drupal. behaviors . replaceMyContent = { attach : function () { $. ajax ({ url : Drupal. url ( ‘my-url' ) , type : 'POST' , dataType : 'json' , success : function (response) { if (response. hasOwnProperty ( 'items' )) { $( “. content-to-replace ” ) . text (response. time ) ; } } }) ; } } ; })(jQuery , Drupal ) ;

@calebporzio

Livewire is not unique ( in a good way )

Basics

namespace Drupal\drupalcamp\Plugin\WireComponent ; use Drupal\wire\View ; use Drupal\wire\WireComponent ; /** * @WireComponent ( * id = "counter", * label = @Translation ("Counter component"), * ) */ class Counter extends WireComponent { public int $count = ; public function render (): ?View { return View:: fromTpl ( ‘counter' ) ; } } <div> <p> {{ count }} </p> </div> …/drupalcamp/src/Plugin/WireComponent/Counter.php …/drupalcamp/templates/wire/counter.html.twig

namespace Drupal\drupalcamp\Plugin\WireComponent ; use Drupal\wire\View ; use Drupal\wire\WireComponent ; /** * @WireComponent ( * id = "counter", * label = @Translation ("Counter component"), * ) */ class Counter extends WireComponent { public int $count = ; public function render (): ?View { return View:: fromTpl ( ‘counter' ) ; } } <div> <p> {{ count }} </p> </div> …/drupalcamp/src/Plugin/WireComponent/Counter.php …/drupalcamp/templates/wire/counter.html.twig

namespace Drupal\drupalcamp\Plugin\WireComponent ; use Drupal\wire\View ; use Drupal\wire\WireComponent ; /** * @WireComponent ( * id = "counter", * label = @Translation ("Counter component"), * ) */ class Counter extends WireComponent { public int $count = ; public function render (): ?View { return View:: fromTpl ( ‘counter' ) ; } } <div> <p> {{ count }} </p> </div> …/drupalcamp/src/Plugin/WireComponent/Counter.php …/drupalcamp/templates/wire/counter.html.twig

<div> {{ wire( 'counter' ) }} … </div> https://wire-drupal.com/docs/rendering-components $wire_counter_component = [ '#type' => 'wire' , '#id' => ‘counter' , ] ;

Actions wire :[dispatched browser event] ="[action]"

<button wire :click ="doSomething" > Do Something </button> <input wire :keydown.enter =“doSomething" > <form wire :submit.prevent ="save" > ... <button> Save </button> </form> <button wire :whatever_custom_event =“doSomething" ></button> <button wire :click ="changeTitle('a string', ' {{ random() }} ')" > Change Title to a random one </button>

<button wire :click ="doSomething" > Do Something </button> <input wire :keydown.enter =“doSomething" > <form wire :submit.prevent ="save" > ... <button> Save </button> </form> <button wire :whatever_custom_event =“doSomething" ></button> <button wire :click ="changeTitle('a string', ' {{ random() }} ')" > Change Title to a random one </button>

<button wire :click ="doSomething" > Do Something </button> <input wire :keydown.enter =“doSomething" > <form wire :submit.prevent ="save" > ... <button> Save </button> </form> <button wire :whatever_custom_event =“doSomething" ></button> <button wire :click ="changeTitle('a string', ' {{ random() }} ')" > Change Title to a random one </button>

<button wire :click ="doSomething" > Do Something </button> <input wire :keydown.enter =“doSomething" > <form wire :submit.prevent ="save" > ... <button> Save </button> </form> <button wire :whatever_custom_event =“doSomething" ></button> <button wire :click ="changeTitle('a string', ' {{ random() }} ')" > Change Title to a random one </button>

<button wire :click ="doSomething" > Do Something </button> <input wire :keydown.enter =“doSomething" > <form wire :submit.prevent ="save" > ... <button> Save </button> </form> <button wire :whatever_custom_event =“doSomething" ></button> <button wire :click ="changeTitle('a string', ' {{ random() }} ')" > Change Title to a random one </button>

<button wire :click ="doSomething" > Do Something </button> <input wire :keydown.enter =“doSomething" > <form wire :submit.prevent ="save" > ... <button> Save </button> </form> <button wire :whatever_custom_event =“doSomething" ></button> <button wire :click ="changeTitle('a string', ' {{ random() }} ')" > Change Title to a random one </button>

namespace Drupal\drupalcamp\Plugin\WireComponent ; use Drupal\wire\View ; use Drupal\wire\WireComponent ; /** * @WireComponent ( * id = "counter", * label = @Translation ("Demo counter component"), * ) */ class Counter extends WireComponent { public int $count = ; public function render (): ?View { return View:: fromTpl ( ‘counter' ) ; } } <div> <p> {{ count }} </p> </div> …/drupalcamp/src/Plugin/WireComponent/Counter.php …/drupalcamp/templates/wire/counter.html.twig

class Counter extends WireComponent { public int $count = ; public function render (): ?View { return View:: fromTpl ( ‘counter' ) ; } } <div> <p> {{ count }} </p> </div>

class Counter extends WireComponent { public int $count = ; public function increment (): void { $this -> count ++ ; } public function render (): ?View { return View:: fromTpl ( 'counter' ) ; } } <div> <span wire :click ="increment" > + </span> <p> {{ count }} </p> </div>

class Counter extends WireComponent { public int $count = ; public function decrement (): void { $this -> count -- ; } public function increment (): void { $this -> count ++ ; } public function render (): ?View { return View:: fromTpl ( 'counter' ) ; } } <div> <span wire :click ="decrement" > - </span> <span wire :click ="increment" > + </span> <p> {{ count }} </p> </div>

class Counter extends WireComponent { public int $count = ; public function decrement ( int $by ): void { $this -> count = $this -> count - $by ; } public function increment (): void { $this -> count ++ ; } public function render (): ?View { return View:: fromTpl ( 'counter' ) ; } } <div> <span wire :click =“decrement(2)” > - </span> <span wire :click ="increment" > + </span> <p> {{ count }} </p> </div>

Cornel Andreev cornel.co twitter.com/hugronaphor drupal.org/u/hugronaphor linkedin.com/in/cornelandreev wire-drupal.com