Bonjour,

J'ai une page listes.index qui contient une liste de boutons qui, lorsqu'on clique dessus, dirigent vers une route listes.show
Actuellement tout fonctionne bien lorsque je clique sur un bouton, je suis redirigé vers ma vue show avec l'id de la liste concernée.

Ce que je veux

J'aimerai que lorsque je clique sur un bouton de la page index, la vue show s'affiche sur cette même page index, un peu sur ce principe là :
https://jsfiddle.net/TyrionGraphiste/M338a/1/

Ce que je fais

  • le lien de mon bouton dans la vue index : href="{{route('listes.show', $liste->id)}}
  • j'ai rajouté dans ma vue index : @include('listes.show', [$liste->id]) (dans une div class="col-md-6")
  • j'ai enlevé le @extends et @section('content') dans ma vue show
  • mon ListeController@show pointe sur return view('listes.show'). Lorsque je modifie par listes.index, ça me dit "undefined variable listes"...

Ce que j'obtiens

Du coup sur le clic du bouton, je n'arrive pas à afficher la page show à l'interieur de la page index. Je tourne en rond...
Quelqu'un aurait il une idée ?

21 réponses


AlexJM
Réponse acceptée

Ah non mais laisse tomber je suis vraiment con x) Faut pas que j'écrive du code à minuit x)

$(function(){
    $('.listeshow-show').click(function(e){
        e.preventDefault();
        var $selected = $('.listeshow-selected');
        $selected.hide();
        $selected.removeClass('listeshow-selected');

        var $newSelected = $($(this).attr('href'));
        $newSelected.show();
        $newSelected.addClass('listeshow-selected');
    });
});

Ca devrait être mieux

ginettebaldoche
Auteur
Réponse acceptée

Whaou ! genial, ça marche ! en fait tu as rajouté $($(this).attr('href')) à la place de $(this). Sans vouloir abuser, pourrais-tu m'expliquer la différence ? avec le .attr('href') tu lui dis d'aller à "l'attribut lien" qui se trouve dans le bouton c'est ça ?
En tout cas merci mille fois Alex pour le temps passé à m'aider.
Bonne soirée

Bonjour,

Tu veux le faire sans recharger la page comme sûr l'example ?

Bonjour,
Si c'est possible, oui, mais sinon, je voudrais déjà que ça me l'affiche avec les données correspondantes à chaque bouton.

J'ai rajouté à ma page index le code suivant :

<style type="text/css">
    .box{
        float:left;
        overflow: hidden;
        background: #ffffff;
        display: none;
    }
    /* Add padding and border to inner content
    for better animation effect */
    .box-inner{
        width: 400px;
        padding: 10px;
        border: 1px solid #a29415;
    }
</style>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script type="text/javascript">
    $(document).ready(function(){
        $(".slide-toggle").click(function(){
            $(".box").animate({
                width: "toggle"
            });
        });
    });
</script>

Mais le pb c'est que quelque soit le bouton sur lequel je clique, le slideToggle m'affiche toujours le dernier élément de ma table, puis ça m'ouvre la page show (avec le bon élément de ma table)... En plus, quand je clique sur un 2eme bouton, ça me referme le premier au lieu de m'afficher le contenu du 2eme.

Salut,

Tu souhaites charger dynamiquement une vue en fonction de l'item sur lequel tu cliques c'est ça ?

Bonjour,
Oui c'est ça, est-ce possible ?

Oui, il te suffit simplement d'utiliser AJAX :)

Pourrais-tu me donner un exemple stp ?

Tu fais un appel AJAX vers ta route qui doit te renvoyer les infos, qui va te générer le HTML correspondant et te le renvoyer. Tu n'auras plus qu'à insérer au bon endroit et le tour est joué.
Cela dit, c'est pas la meilleure solution. Tu as beaucoup de listes à charger ? Car sinon tu peux précharger les listes dans la page, et les afficher / cacher cia un jeu de JS / CSS. Rien de bien compliqué.

L'ajax est une bonne idée,
Mais sinon tu peux aussi inclure directement la view fille dans la view mère, l'entourer d'un div display none et changer le display en js

@AlexM Oui, cela rejoint ma seconde remarque et c'est une bonne solution également. Le chargement de la page sera un peu plus long, mais toutes les data seront là. A lui de voir maintenant comment il préfère procéder :)

@betaWeb mon mauvais, je n'avais pas vu :o

Bonjour et merci pour vos réponses.
J'ai essayé ce que vous me proposez en faisant ça dans ma vue index :

    function listechange() {
      if (document.getElementById("listeshow").style.display == "block")
      {
        document.getElementById("listeshow").style.display = 'none';
        document.getElementById("listeshow").style.visibility = 'none';
      }
      else
     {
        document.getElementById("listeshow").style.display = 'block';
        document.getElementById("listeshow").style.visibility = 'visible';
      }
    }

et

        @foreach ($listes as $liste)
          <tr>
            <td class="text-primary">{{ $liste->name }}</td>
            <td><a class="btn btn-outline-warning pull-right", onclick="javascript:listechange()"><span><i class="fa fa-eye", title="Voir"></i></span></a></td>
            .....
          </tr>
        @endforeach
        ....
  </div>
  <div class="col-md-7">
    <div class="control-group" id="listeshow" name="listeshow" style="display:none">
    @include('listes.show', [$liste->id])
    </div>
  </div>

ça m'affiche bien le contenu de la page show mais systématiquement avec le dernier élément de ma table et non pas l'élément sur lequel je clique et lorsque je clique sur un autre bouton, ça le masque au lieu d'afficher son contenu. Je ne sais pas si je suis très claire là ?
En gros j'aimerai bien reproduire l'effet de cette page : https://jsfiddle.net/TyrionGraphiste/M338a/1/
sachant que le menu correspond en fait à mes boutons et que ce qui s'affiche quand on clique est le contenu de ma page show avec l'id de chaque "liste".
Pourriez-vous m'aider à corriger mon code ?

Tout d'abord, si display est mis à none, visibility est "automatiquement" mise à hidden, enfin je veux dire que tu ne peux pas afficher un truc qui n'est pas dans le layout

Ce que tu veux c'est genre :
Tu as deux boutons : p1 et p2 (par exemple)
Tu as deux divs
Tu veux que p1 affiche le premier div et masque le deuxième et que p2 fasse l'inverse ?

En fait j'ai un tableau qui récupère les listes depuis la base de données. à l'affichage ça me donne :
liste1 voir(btn avec lien vers le contenu de la liste1)
liste2 voir(btn avec lien vers le contenu de la liste2)
Liste3 voir(btn avec lien vers le contenu de la liste3)
etc.... autant qu'il y a de listes dans la base de données

le bouton "voir" au départ, dirigeait sur ma route listes.show avec $liste->id (et m'amenait donc sur une autre page)
Je veux que le contenu de chaque liste s'affiche dans la même page que "liste1 voir" (c'est à dire la page listes.index) et que lorsque je clique sur le bouton voir de la liste1, ça m'affiche le contenu de la liste1, puis si je clique sur le bouton voir de la liste2, ça m'affiche le contenu de la liste2 etc...
Donc dans la page je crée une div qui récupère ma page listes.show (@include ('listes.show ', [$liste->id]).
Maintenant à l'écran j'ai :
liste1 voir si je clique j'ai le contenu de la liste3
liste2 voir si je clique j'ai le contenu de la liste3
Liste3 voir si je clique j'ai le contenu de la liste3

et ce que je veux c'est :
liste1 voir si je clique j'ai le contenu de la liste1
liste2 voir si je clique j'ai le contenu de la liste2 (et la liste1 se cache)
Liste3 voir si je clique j'ai le contenu de la liste3 (et la liste2 se cache)

Est-ce que tu comprends mieux mon problème à présent ? Je m'arrache les cheveux depuis plusieurs jours sans trouver de solution malgré mes recherches...

Alors déjà du coup tu dois faire aussi un foreach sur les listes ici

<div class="control-group" id="listeshow" name="listeshow" style="display:none">
    @include('listes.show', [$liste->id])
</div>

afin d'afficher le contenu de toutes les listes

Ensuite, tu peux ajouter l'id de la liste à l'id du listeshow, et on va aussi lui mettre une petite class "listeshow":

<div class="control-group listeshow" id="listeshow-{{$liste->id}}" name="listeshow" style="display:none">
    @include('listes.show', [$liste->id])
</div>

Ensuite sur ton lien (attention pour afficher le style du lien il faut tjs avoir un href dedans sur certains navigateurs), tu peux mettre l'id du div en href et on va aussi virer le onclick qu'on va mettre directement dans le javascript pour avoir accès à l'événement (donc on lui met une classe afin d'y avoir accès):

<a class="btn btn-outline-warning pull-right listeshow-show" href="#listeshow-{{$liste->id}}"><span><i class="fa fa-eye" title="Voir"></i></span></a>

(et comme ça, y'a pas de "," entre les différents attributs)

Finalement, pour le js, tu dois afficher l'élément référencé dans href et masquer celui qui a été affiché :

//On ajoute l'événement click à chacun des liens
var links = document.querySelectorAll('.listeshow-show');
for (var i = links.length - 1; i >= 0; i--) {
    links[i].addEventListener('click', function(e){
        e.preventDefault();//Empêche le navigateur d'aller sur le lien, après si tu veux aller directement au contenu de la liste, tu peux virer cette ligne
        // On choppe l'élément actuellement sélectionné, on le masque et on retire la class
        var selected = document.querySelector('.listeshow-selected');
        selected.style.display = 'none';
        selected.classList.remove('listeshow-selected');

        // On choppe l'élément rérérencé dans href (e.target récupère le lien sur lequel on a cliqué), on l'affiche et on ajoute la class
        var newSelected = document.querySelector(e.target.getAttribute('href'))
        newSelected.style.display = 'block';
        newSelected.classList.add('listeshow-selected');
    });
}

Bon j'ai pas testé mais ça m'a l'air pas mal, si jamais t'a une erreur n'hésite pas

Note1: si tu veux de la meilleure compatibilité pour le js, je t'invite à mettre un polyfill pour le classList, on en trouve sur le net
Note2: si tu veux faire plus propre, tu peux mettre le display: block dans la class listeshow-selected et mettre le display: none dans la class listeshow

Merci beaucoup Alex pour ta réponse ! Alors j'ai fait les modifs que tu m'as indiqué, je n'ai pas d'erreur, le lien rajoute bien le n° de la liste : http://localhost:8000/listes#listeshow-38 par exemple, mais... rien ne s'affiche à l'écran.
J'ai mis comme tu m'as dit le foreach pour la div :

  @foreach ($listes as $liste)
  <div class="col-md-7">
    <div class="control-group listeshow" id="listeshow-{{$liste->id}}" name="listeshow" style="display:none">
        @include('listes.show', [$liste->id])
    </div>
  </div>
  @endforeach

J'ai recopié le script js dans ma page, mais lorsque je clique sur un bouton, le lien se modifie bien mais rien ne s'affiche...
Est-ce que ça viendrait de mon script source ? :

<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>

Pas de problèmes,

Tu dois sûrement avoir une erreur sur le script js (je suis pas vraiment doué pour le js natif ^^), mais si tu utilises jquery j'vais te le modifier pour qu'il soit plus facile :

$(function(){
    $('.listeshow-show').click(function(e){
        e.preventDefault();
        var $selected = $('.listeshow-selected');
        $selected.hide();
        $selected.removeClass('listeshow-selected');

        var $newSelected = $(this);
        $newSelected.show();
        $newSelected.addClass('listeshow-selected');
    });
});

Normalement ça devrait fonctioner mais si ça ne fonctionne pas tu auras une erreur dans la console

Bonjour Alex, alors maintenant : lorsque je clique sur un premier bouton, il ne se passe rien, puis quand je clique sur un 2eme, le premier bouton s'efface... si je clique à nouveau sur un bouton le précédent sur lequel j'ai cliqué s'efface...

Pas de prob :)

En faite this représente l'élément sur lequel s'applique l'évémenent donc $(this) l'élement jquery sur lequel s'applique l'événement, donc on prends le lien avec .attr('href'), celui-ci représentant l'id $($(this).attr('href')) représente l'élement représenté dans l'attribut href ;)

Pense à mettre les messages contenant la solution à ton problème en résolu aussi, afin que les gens qui passent voir le poste ne doivent pas chercher les réponses ;)