web-dev-qa-db-fra.com

Laravel - Form Input - Multiple select pour une relation à plusieurs

L'une des exigences d'une application que je suis en train de créer est pour une entrée de formulaire qui prend un nombre variable d'éléments pour un seul champ. Par exemple, les sports que je pratique sont ('Soccer', 'Tennis', 'Croquet'). 

Il existe un nombre fini de sports pouvant être pratiqués (sans doute), donc ces éléments doivent être sélectionnés dans une liste de type "déroulante" dans la saisie de formulaire.

En aval de ce formulaire, il y aura deux tables qui ont une relation un à plusieurs. Ainsi, à partir de ce qui précède, la table "utilisateur" aurait une seule ligne, tandis que la table "utilisateur_sports" aurait trois lignes. Celles-ci seraient alors liées par le champ id de la table user.


Je n'ai pas été capable de trouver le type de fonctionnalité où cela peut être réalisé dans la documentation (peut-être que je ne cherche pas la bonne chose). Ci-dessous, le plus proche que j'ai trouvé, mais uniquement pour sélectionner un élément unique dans une liste déroulante.

http://laravel.com/docs/html#drop-down-lists


Existe-t-il une solution de contournement qui me permettra de mettre en place cet élément de formulaire en utilisant le framework Laravel?

Sinon, existe-t-il d'autres moyens de réaliser ce type de fonctionnalité sans nuire à l'expérience utilisateur?

20
datavoredan

Je suis d'accord avec user3158900 et je ne diffère que légèrement de la manière dont je l'utilise:

{{Form::label('sports', 'Sports')}}
{{Form::select('sports',$aSports,null,array('multiple'=>'multiple','name'=>'sports[]'))}}

Cependant, selon mon expérience, le troisième paramètre de la sélection est une chaîne uniquement. Par conséquent, pour repeupler des données pour une sélection multiple, j'ai dû procéder de la manière suivante:

<select multiple="multiple" name="sports[]" id="sports">
@foreach($aSports as $aKey => $aSport)
    @foreach($aItem->sports as $aItemKey => $aItemSport)
        <option value="{{$aKey}}" @if($aKey == $aItemKey)selected="selected"@endif>{{$aSport}}</option>
    @endforeach
@endforeach
</select>
48
SamMonk

@SamMonk, votre technique est excellente. Mais vous pouvez utiliser laravel form helper pour le faire. J'ai une relation client et chiens.

Sur votre contrôleur

$dogs = Dog::lists('name', 'id');

Sur le client créer créer, vous pouvez utiliser.

{{ Form::label('dogs', 'Dogs') }}
{{ Form::select('dogs[]', $dogs, null, ['id' => 'dogs', 'multiple' => 'multiple']) }}

Le troisième paramètre accepte une liste de tableau d'un puits. Si vous définissez une relation sur votre modèle, vous pouvez le faire:

{{ Form::label('dogs', 'Dogs') }}
{{ Form::select('dogs[]', $dogs, $customer->dogs->lists('id'), ['id' => 'dogs', 'multiple' => 'multiple']) }}

Mise à jour pour Laravel 5.1

La méthode lists renvoie maintenant un objet Collection . Mise à niveau vers 5.1.0

{!! Form::label('dogs', 'Dogs') !!}
{!! Form::select('dogs[]', $dogs, $customer->dogs->lists('id')->all(), ['id' => 'dogs', 'multiple' => 'multiple']) !!}
41
Sushant Aryal

Laravel 4.2

@ SamMonk a donné la meilleure alternative, j'ai suivi son exemple et construit le dernier morceau de code

<select class="chosen-select" multiple="multiple" name="places[]" id="places">
    @foreach($places as $place)
        <option value="{{$place->id}}" @foreach($job->places as $p) @if($place->id == $p->id)selected="selected"@endif @endforeach>{{$place->name}}</option>
    @endforeach
</select>

Dans mon projet, je vais avoir beaucoup de relations de table comme celle-ci, alors j'ai écrit une extension pour le garder propre. Pour le charger, placez-le dans un fichier de configuration tel que "app/start/global.php". J'ai créé un fichier "macros.php" sous le répertoire "app /" et je l'ai inclus dans le EOF de global.php

// app/start/global.php
require app_path().'/macros.php';

// macros.php
Form::macro("chosen", function($name, $defaults = array(), $selected = array(), $options = array()){

    // For empty Input::old($name) session, $selected is an empty string
    if(!$selected) $selected = array();

    $opts = array(
        'class' => 'chosen-select',
        'id' => $name,
        'name' => $name . '[]',
        'multiple' => true
    );
    $options = array_merge($opts, $options);
    $attributes = HTML::attributes($options);

    // need an empty array to send if all values are unselected
    $ret = '<input type="hidden" name="' . HTML::entities($name) . '[]">';
    $ret .= '<select ' . $attributes . '>';
    foreach($defaults as $def) {
        $ret .= '<option value="' . $def->id . '"';
        foreach($selected as $p) {
            // session array or passed stdClass obj
            $current = @$p->id ? $p->id: $p;
            if($def->id == $current) {
                $ret .= ' selected="selected"';
            }
        }
        $ret .= '>' . HTML::entities($def->name) . '</option>';
    }
    $ret .= '</select>';
    return $ret;
});

Usage

Liste sans éléments présélectionnés (créer une vue)

{{ Form::chosen('places', $places, Input::old('places')) }}

Présélections (vue d'édition)

{{ Form::chosen('places', $places, $job->places) }}

Utilisation complète

{{ Form::chosen('places', $places, $job->places, ['multiple': false, 'title': 'I\'m a selectbox', 'class': 'bootstrap_is_mainstream']) }}
5
Ben K.

Une sélection multiple est en réalité simplement une sélection avec un attribut multiple. Dans cet esprit, cela devrait être aussi simple que ...

Form::select('sports[]', $sports, null, array('multiple'))

Le premier paramètre est juste le nom, mais après sa résolution avec le [] le retournera sous forme de tableau lorsque vous utiliserez Input::get('sports')

Le deuxième paramètre est un tableau d'options sélectionnables.

Le troisième paramètre est un tableau d'options que vous souhaitez présélectionner.

Le quatrième paramètre est en train de définir cela comme un menu déroulant de sélection multiple en ajoutant la propriété multiple à l'élément de sélection réel.

4
user3158900

Ma solution, c’est make avec jQuery choisi et bootstrap, l’id est pour jQuery choisie, testée et fonctionne, j’ai eu des problèmes pour concaténer @foreach mais travaille maintenant avec un double @foreach et un double @if:

  <div class="form-group">
    <label for="tagLabel">Tags: </label>
    <select multiple class="chosen-tag" id="tagLabel" name="tag_id[]" required>
      @foreach($tags as $id => $name)
        @if (is_array(Request::old('tag_id')))
                <option value="{{ $id }}" 
                @foreach (Request::old('tag_id') as $idold)
                  @if($idold==$id)
                    selected
                  @endif 
                @endforeach
                style="padding:5px;">{{ $name }}</option>
        @else
          <option value="{{ $id }}" style="padding:5px;">{{ $name }}</option>
        @endif
      @endforeach
    </select>
  </div>

c’est le code choisi par jquery (le code blade.php n’a pas besoin de ce code pour fonctionner)

    $(".chosen-tag").chosen({
  placeholder_text_multiple: "Selecciona alguna etiqueta",
  no_results_text: "No hay resultados para la busqueda",
  search_contains: true,
  width: '500px'
});
1

Cela pourrait être une meilleure approche que la réponse la plus fréquente si vous devez comparer 2 tableaux de sortie mais que vous utilisez le premier tableau pour renseigner les options.

Cela est également utile lorsque vous avez un index (clé) non numérique ou offset.

<select name="roles[]" multiple>
    @foreach($roles as $key => $value)
        <option value="{{$key}}" @if(in_array($value, $compare_roles))selected="selected"@endif>
            {{$value}}
        </option>
    @endforeach
</select>
0
Tom van Tilburg