Bonjour à tous,

J'ai 2 tables de ma base de données liées entre elles par un id. Dans ma vue j'affiche certaines données (numériques ou textuelles) de la table 1 (qui est préremplie), ainsi que certaines données de la table 2 (un ou plusieurs id(s) ainsi qu'un poids par id que l'utilisateur à choisi auparavant).
Mon souci : je dois effectuer un calcul pour chaque id ainsi que la somme de ces calculs. En fonction du poids que l'utilisateur à choisi pour chaque id, l'affichage des données de la table 1 doit être modifié.

Exemple :
L'utilistateur à choisi un poids de 50gr pour un aliment 1 (table 2)
Puis il a choisi un poids de 120gr pour un aliment 2 (table 2)
etc...

Les valeurs affichées par défaut (table 1) sont les valeurs pour 100gr

Ce que je fais

Voici mon script (qui fonctionne) lorsque l'utilisateur choisi son poids :

<script type="text/javascript">
  $(function () {
    $("#calcul").click(function (e) {
      e.preventDefault();
      var valeur = $("#myTextBox").val();
      if (valeur == "" || valeur == 0) {
        alert('Entrez une valeur dans la cellule !');
        return;
      }

      $("#nutrition > tbody > tr").each(function () {
        var valeurOrigin = parseFloat($(this).find("td").eq(1).text().replace(",", "."));
        var newValeur;
        if ($.isNumeric(valeurOrigin) === true) {
          newValeur = valeurOrigin*valeur/100;
          newValeur = Math.ceil(newValeur*1000)/1000;
          //newValeur = "<"+(valeurOrigin*valeur/100);
        } else {
          newValeur = $(this).find("td").eq(1).text();
        }

        $(this).find("td").eq(2).html(newValeur);
      });
    });
  });

et un bout de ma vue :

<table class="table table-striped" id="nutrition">
  <thead>
    <tr>
      <th>Aliments</th>
      <th>Poids</th>
      <th>Energie kJ</th>
      <th>Vitamine B12</th>
    </thead>

      <tbody class="text-primary">
      @foreach ($menu->ciquals as $menuCiqual)
      <tr><td>{{ $menuCiqual->ciqual->name}}:</td><td><strong>{{ $menuCiqual->quantite}}gr</strong></td>
        <td onload="">{{ $menuCiqual->ciqual->energie_kJ  }}</td>
        <td>{{ $menuCiqual->ciqual->vit_b12 }}</td>
      </tr>
      @endforeach
      <tr><td>Total</td><td><strong>{{ $menuCiqual->where('menu_id', $menuCiqual->menu->id)->sum('quantite')}}gr</strong></td></tr>
    </tr>
      </tbody>
    </table>

Ce que je veux

Dans ma vue j'aimerais afficher dans un tableau avec les valeurs calculées pour chaque aliment (valeur calculée = valeur initiale x poids choisi / 100) ainsi que la somme des valeurs calculées.

Ce que j'obtiens

Je ne sais pas comment modifier mon code pour arriver au résultat souhaité.
Je ne maitrise pas du tout le javascript, je débute...si quelqu'un pouvait m'aiguiller ?
Merci d'avance !

14 réponses


hello,
d'après ce que je comprends ton système est simple : il doit calculer un ratio (règle de trois).
c le pourquoi de ma première question : pourquoi 2 tables ?
ensuite le principe sera de calculer ton ratio en fct d'une valeur rentrée par l'utilisateur. est-ce bien ça ?
si oui, il faut mettre un écouteur sur le champ modifiable et lui attribuer les fonctions de modifications... pour l'instant tranquille...
le hic : je lis :

 @foreach ($menu->ciquals as $menuCiqual)
      <tr><td>{{ $menuCiqual->ciqual->name}}:</td><td><strong>{{ $menuCiqual->quantite}}gr</strong></td>
        <td onload="">{{ $menuCiqual->ciqual->energie_kJ  }}</td>
        <td>{{ $menuCiqual->ciqual->vit_b12 }}</td>
      </tr>
      @endforeach
      <tr><td>Total</td><td><strong>{{ $menuCiqual->where('menu_id', $menuCiqual->menu->id)->sum('quantite')}}gr</strong></td></tr>

qui sont clairement des appels de function à un framework.
bref : tu développes dans quel environnement ?
car pour faire une règle de trois, il n'y a pas à se prendre la tête, par contre si tu veux modifier un "model" ds un framework il y a 2 3 règles à suivre....

Bonjour saibe et merci pour ta réponse.
J'utilise le framework laravel.
J'ai 2 tables car :

  • une est préremplie avec, pour chaque id, des valeurs par défaut pour un poids fixe de 100gr
  • l'autre contient des données choisies par l'utilisateur, notament des ids de la table 1 avec le poids qu'il a pu personnaliser grâce à une textbox . Ces infos sont sauvegardées dans ma table 2.
    Dans ma vue, actuellement je récupère les valeurs par défaut (table 1) des ids choisis par l'utilisateur, mais je voudrais qu'ils soient affichés "calculés" en fonction du poids qu'il a choisi (qui est stocké dans la table 2). Puis dans ma ligne "total", qu'il y ait le total de chaque id par colonne.

hello,
donc seule ta 2ème colonne ("Poids") est modifiable et tout le reste se calcule en fonction...
tu ne dois récupérer que la qté dans ta table 2... c ça ?
ce que je ferais : mettre une class à toutes tes colonnes et un input à l'intérieur de ta colonne "poids".
tu écoutes le change sur cet input et quand c le cas tu lances ton calcul.
car d'après ce que je lis tu as un bouton '#calcul' qui quand tu le cliques récupère une valeur de ta "#myTextBox" mais tu n'en fais rien...
je rajouterais un dataset à ta colonne "aliment" avec les infos utiles (genre le KJ/100gr...)
tu auras donc toutes les infos dans ta table html (plus besoin de faire de requêtes...) ce sera dynamique et plus simple à calculer...
un exemple :

<table class="table table-striped" id="nutrition">
  <thead>
    <tr>
      <th>Aliments</th>
      <th>Poids</th>
      <th>Energie kJ</th>
      <th>Vitamine B12</th>
    </tr> // tu l'as pas fermé ds ton code ?
    </thead>

      <tbody class="text-primary">
      @foreach ($menu->ciquals as $menuCiqual)
        <tr class="aliment" data-energie="100" data-vitamine="12"> // il faudra récupérer les infos de ta table 1
            <td class="name">{{ $menuCiqual->ciqual->name}}:</td>
            <td class="poids"><input type="text" value="{{ $menuCiqual->quantite}}" />gr</td>
            <td class="nrj">{{ $menuCiqual->ciqual->energie_kJ  }}</td>
            <td class="vb12">{{ $menuCiqual->ciqual->vit_b12 }}</td>
        </tr>
      @endforeach
      <tr class="totaux">
        <td>Total</td>
        <td class="poids"></td>
        <td class="nrj"></td>
        <td class="vb12"></td>
      </tr>

      </tbody>
    </table>

et ton js :

$(function () {
    $('.poids input').change(function(){
         faisLesCalculs();
    });
     faisLesCalculs(); // pour les lancer à l'init
});

function faisLesCalculs(){
    var poidsTot = 0;
    var nrjTot = 0;
    $('#nutrition .aliment').each(function(){
        poids = $(this).find('.poids input').val();
        // mettre tes vérif ici et si c bon continuer
       poidsTot+= poids;

        nrj = $(this).data('energie')*poids/100; // du moins ton calcul de ratio et l'arrondi qui va bien...
        $(this).find('.nrj').html(nrj);
        nrjTot+= nrj;
    });
    // tu peux mettre des vérif aussi ici
    $('#nutrition .totaux .poids').html(poidsTot);
    $('#nutrition .totaux .nrj').html(nrjTot);
}

en gros....

Super ! merci beaucoup Saibe, ça commence à être mieux, mais j'ai encore certains pb d'affichage :
Toutes les valeurs de la table 1 qui contiennent une virgule ne s'affichent pas dans la page.
Dans la table 1 il y a certaines cellules qui comporte du texte : ces textes ne s'affichent pas dans la page.
Le total du poids ne fonctionne pas. Si alim1 = 20gr, alim2 = 50gr, alim3 = 120gr... ça m'affiche dans le total 2050120
Certains totaux ont trop de chiffres après la virgule.
Un certain nombre de totaux sont faux. C'est vraiment bizarre...
Comme un visuel vaut mieux qu'un long discours, je te met 2 visuels du résultat obtenu pour l'instant :
https://1drv.ms/f/s!AlgxWAMDiCCmgqZr3ALNPfIbZ-c70A

;) pas mal du tout...
pour le poids tu peux tenter une conservion string -> float avant de l'additionner au poidsTot :

poids = $(this).find('.poids input').val()*1; // vieille technique
ou
poids = $(this).find('.poids input').val();
poids = parseFloat(poids); // si c un decimal
ou
poids = parseInt(poids); // si c un entier

ensuite tu peux arrondir les résultats :

poidsTot = Math.ceil(poidsTot*100)/100; // exces
poidsTot = Math.round(poidsTot*100)/100; // arrondi normal

regarde ici pour les arrondis
tu avais employé tout ça dans ton code de départ...
ct les // mettre tes vérifs dans l'exemple que je t donné

tu pourrais poster tes codes html et js ?

Vu la longueur du code je te l'ai mis en fichier joint :
https://1drv.ms/u/s!AlgxWAMDiCCmgqZs0tnw5FX7yzkaVw

;) en effet...
tu as apporté les modifications préconisées ?

Saibe, je suis novice en js, je ne comprends pas ce que tu veux dire par modifications préconisées.
J'ai essayé de remettre la partie de code :

var valeurOrigin = parseFloat($(this).find("td").eq(1).text().replace(",", "."));
        var newValeur;
        if ($.isNumeric(valeurOrigin) === true) {
          newValeur = valeurOrigin*valeur/100;
          newValeur = Math.ceil(newValeur*1000)/1000;
          //newValeur = "<"+(valeurOrigin*valeur/100);
        } else {
          newValeur = $(this).find("td").eq(1).text();
        }

        $(this).find("td").eq(2).html(newValeur);

après celui-ci :

$('#nutrition .aliment').each(function(){
        poids = $(this).find('.poids input').val();

Mais ça ne fonctionne pas et je ne sais pas comment le modifier...

;) pas de soucis, on est là pour apprendre... perso, j'apprends à comprendre ;)
quand tu me dis :

J'ai essayé de remettre la partie de code :

suivit de ton code avec la condition if... tu comprends ce que tu fais ?

tu rajoutes

après celui-ci :

oui, ok, mais comment ?

Bonsoir.
Personnellement, j'aimerais bien connaître l'utilité de la ligne suivante :

newValeur = Math.ceil(newValeur * 1000) / 1000;

Car je ne comprends absolument pas à quoi ça peut servir de multiplier une valeur par 1000 pour ensuite diviser le résultat par 1000.
Par exemple, si tu multiplies 300 par 1000 et que tu divises le résultat par 1000, tu obtiendras la même valeur qu'au départ, soit :

  • 300 x 1000 = 300 000
  • 300 000 / 1000 = 300

Pour faire simple, tu fais faire un calcul totalement inutile.

@Lartak : c une technique pour arrondir des float ; ici au millième à l'excès...
Math.ceil(3.12578954 * 1000) = 3126 et 3126/1000 = 3.126

Bonjour Saibe,
"tu comprends ce que tu fais ?" : ce que je comprends dans mon if :
si la valeur d'origine est numérique, alors la nouvelle valeur sera le calcul (VO x poids/100)
Le résultat de la nouvelle valeur sera arrondi à 3 chiffres après la virgule
Sinon (si la VO n'est pas numérique), la nouvelle valeur est récupérée et identique à celle d'origine

Avant le if, on demande de remplacer les "," par des "." pour les nombres décimaux (sinon ils ne s'affichent pas comme c'est le cas actuellement..)

tu me dis : après ce code :

$('#nutrition .aliment').each(function(){
        poids = $(this).find('.poids input').val();

tu rajoutes après "oui, ok, mais comment ?"
Ben, justement, c'est là le pb, c'est que je ne sais pas modifier mon code à partir de celui-là....
Toi tu utilises "poids" et moi "valeur d'origine" et "nouvelle valeur"...

hello,
tout simplement comme ça, je reprend tes vérifs :

$('#nutrition .aliment').each(function(){
        poids = $(this).find('.poids input').val();
        poids = poids.replace(',', '.'); // remplace les ',' par des points au cas où
        poids = $.isNumeric(poids)?poids:0; // si c un nombre on le conserve sinon on le passe à 0 pour que ça ne bloque pas la suite
        ...
        poidsTot+= poids;
        ...
 });
 poidsTot = Math.ceil(poidsTot*1000)/1000; // arrondi
 ...

c une idée, après si la valeur n'est pas numérique tu peux te faire un système d'alerte...