【问题标题】:Livewire/Alpine Dynamic # of Toggle BindingLivewire/Alpine Dynamic # of Toggle Binding
【发布时间】:2021-07-13 06:09:41
【问题描述】:

我有一个显示toggle switches 编号的表单。

开关的数量是动态的,基于表中的“权限”。如何绑定这些,以便在单击它们时将数据发送回 livewire?我发现的“非动态”答案是 x-data="{isChecked: @entangle('foo')}" 但如果我有未知数量的项目而不是单个“foo”,这显然不起作用.

我尝试了一种方法 wire:click="update({{ $value->id }})" 但这只会将已单击元素的 id 传回给 livewire,而不是它的状态(打开或关闭) )。

@foreach($permissions as $key => $value)
   <div>
      <span>
         <span>{{ $value->name }}</span>
         <span>{{ $value->description }}</span>
      </span>
      <button type="button"
         x-data="{isChecked: {{ $value->allowed ? 1 : 0 }}}"
         @click="isChecked = !isChecked"
         {# wire:click? doesn't send state #}
         wire:click="update"
         :class="{'bg-liteblue': isChecked, 'bg-gray-200': !isChecked }"
         class="relative..."
         role="switch"
         :aria-checked="isChecked"
         aria-labelledby="availability-label">
         <span class="sr-only">Use setting</span>
         <span aria-hidden="true"
            :class="{'translate-x-5': isChecked, 'translate-x-0': !isChecked }"
            class="translate-x-5 transition ease-in-out duration-200"></span>
      </button>
   </div>
@endforeach

我希望每个切换都在单击时更新数据库(而不是在最终提交中)。如何将状态传递回 livewire 控制器?

【问题讨论】:

    标签: laravel-livewire alpine.js


    【解决方案1】:

    我相信您需要在 x-data 行中使用“@entangle”。以下是https://laravel-livewire.com/docs/2.x/alpine-js 上大约 1/2 处的示例。这将 javascript 变量 = 打开到 livewire 公共属性 $showDropdown 纠缠在一起。当您更改 open 的值时,公共属性 $showDropdown 将更改为等效于 open。但是,我认为交流只是一种方式——apine to livewire。

    <div x-data="{ open: @entangle('showDropdown') }">
    

    或者你可以使用类似的东西

    <button x-on:click="$wire.someMethod($value->id)">xxxxxxx</button>
    

    参数将确定您单击了哪个切换。 livewire 方法 - someMethod() - 然后会将选择保存在数据库中。

    我也有类似的问题。以下是我正在尝试的。当点击事件被触发时,它会切换 alpine 变量“enableit”。 alert(enableit) 显示正在切换的状态。但是 alert('{{ $isEnabled }}') 显示为空白。但是,如果我查看控制台中返回的 json,我会看到 $isEnabled 属性被切换,但与 enableit 变量相反。

    @props([
        'choice' => 'Make Administrator?',
        'desc' => 'We encourage you to make your spouse / partner an administrator',
        'isEnabled' => false,
    ])
    <div
        x-data="{ open: @entangle('showToggleButton').defer,
                  enableit: @entangle('isEnabled')}"
        class="flex items-center justify-between"
    >
      <span x-show="open" class="flex-grow flex flex-col" id="availability-label">
        <span class="text-sm font-medium text-gray-900 mr-4">{{ $choice }}</span>
        <span class="text-sm text-gray-500 mr-4">{{ $desc }}</span>
      </span>
        <!-- Enabled: "bg-indigo-600", Not Enabled: "bg-gray-200" -->
        <button x-show="open" type="button"
                @click="enableit = !enableit; alert(enableit); alert('{{ $isEnabled }}')"
                class="{{ ($isEnabled) ? 'bg-indigo-600' : 'bg-gray-200' }}  relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
                role="switch" aria-checked="enableit" aria-labelledby="availability-label">
            <span x-show="open"  class="sr-only">Use setting</span>
            <!-- Enabled: "translate-x-5", Not Enabled: "translate-x-0" -->
            <span x-show="open" aria-hidden="!enableit"
                  class="{{ ($isEnabled) ? 'translate-x-5' : 'translate-x-0' }} pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200"></span>
        </button>
    </div>
    

    顺便说一句,你提到了

    # wire:click? doesn't send state #
    

    我相信你应该在 alpine 组件中使用 $wire.click。

    【讨论】:

      【解决方案2】:

      我用一个名为“permission-toggle”的子组件解决了这个问题,这样每个切换都可以负责保存它的状态而不是一个数组,然后在父组件中实例化它

      @foreach($permissions as $permission)
      
              <livewire:permission-toggle :group="$selectedGroup" :permission="$permission" :key="$selectedGroup.'.'.$permission->slug">
      
      @endforeach
      

      父“permission-form”组件负责从数据库中获取所有权限(因此只有一个大的负载调用),然后每个单独的“permission-toggle”组件负责更新自身。 (个别数据库调用)权限切换的livewire控制器如下

      class PermissionToggle extends Component
      {
          public bool   $checked;
          public string $name;
          public string $description;
          public string $slug;
          public string $group;
      
          public function mount($permission)
          {
              $this->checked     = $permission->allowed;
              $this->name        = $permission->name;
              $this->description = $permission->description;
              $this->slug        = $permission->slug;
          }
      
          public function updating($a, bool $checked)
          {
              $group = Group::where('slug', $this->group)->first();
      
              if($checked === true)
                  $group->assignPermissions($this->slug);
              else
                  $group->revokePermissions($this->slug);
          }
      
          public function render()
          {
              return view('livewire.permission-toggle');
          }
      } 
      

      【讨论】:

        【解决方案3】:

        有几个层次可以回答这个问题。第一个是:

        为什么@entangle?

        如果您要通过 Livewire 同步数据,那么严格来说(至少形成我从您的代码中理解的内容),您不需要将数据与 Alpine 纠缠在一起。

        第二层是:

        如果你坚持使用@entangle

        您不需要创建一个全新的组件。你可以纠缠一个数组(和一个数组数组,一个数组数组):

        毫无疑问,您接受的解决方案有效。但在我看来,这看起来是一个相当冗长的解决方案。我不喜欢掩埋类/文件层来解决一个应该“虽然”作为一个单一概念的解决方案。当您必须翻阅多个文件时,它会使长期维护更加耗时。 (也许是个人喜好。)

        我的处理方法如下。在原始 Livewire 组件中定义一个数组:

        class PropertiesPage extends Component
        {
            // in the real world, this array would be populated from a DB
            public array $permissions = [
                'inventory' =>  [ // group level
                    'view_inv' => [ // permission level
                        'description' => 'View Inventory',
                        'slug'        => '/viewinv',
                        'is_checked'  => true,
                    ],
                    'update_inv' => [
                        'description' => 'Modify Inventory',
                        'slug'        => '/modinv',
                        'is_checked'  => false,
                    ],
                ],
            ];
        

        在您的 blade.php 文件中,然后将整个数组纠缠在一起:

            <div x-data="dbPermissions: @entangle('permissions')">
                <p>Blah...</p>
            </div>
        

        然后,您可以使用 Blade 的 @foreach 以与您在问题中所做的方式类似的方式循环遍历数组。 但是,正如我在上面第一点中强调的那样,如果您的逻辑和同步发生在 Blade/Livewire 中,为什么还要打扰 @entangle-ing?当然,如果想要@entangle 首先是使用Alpine 的循环解决方案,也就是说你可以这样做:

            <template x-for="(perms, group) in dbPermissions">
                <p x-text="group"></p>
                <template x-for="(props, permId) in perms">
                    <input type="radio" x-model="dbPermissions[group][permId].is_checked">
                </template>
            </template>
        

        当然,我所有的代码都是伪代码,因为我没有完全掌握您的实际解决方案。我在这个网站上的意图始终是公开分享这些概念,而不是将您的特定问题解决到一个 T。

        【讨论】:

        • 刚刚注意到这个答案与我最近给出的另一个答案有多么相似:stackoverflow.com/questions/69337244/…。事实上,潜在的问题有多相似。我的另一个答案包含我测试的实际代码,而不是基于伪代码。
        猜你喜欢
        • 2021-05-12
        • 1970-01-01
        • 1970-01-01
        • 2021-10-24
        • 2021-09-02
        • 2020-01-25
        • 2021-01-22
        • 1970-01-01
        • 2021-10-21
        相关资源
        最近更新 更多