2015-09-19 16 views
12

Ho impostato uno scenario molto simile all'esempio di Riga modificabile dal sito demo x-editable. In questo scenario, a c'è una semplice tabella con tre colonne per i dati e una quarta per i pulsanti modifica ed elimina. Un terzo pulsante al di fuori della tabella aggiunge una riga alla tabella. Quando il modulo è modificabile, le colonne di dati diventano modificabili (la caratteristica principale della libreria modificabile x). Per questa demo, la prima colonna diventa una semplice modifica del testo e le seconde due colonne diventano elenchi a discesa.ng-repeat con controller per ogni riga della tabella: come accedere agli elementi del modulo modificabili x?

La tabella viene creata eseguendo una ripetizione su un modello di riga. Devo fare alcune cose diverse che implicano tutte l'accesso all'ambito creato dalla ng-repeat. Ho bisogno di

  • rilevare quando la riga è modificabile e quando non lo è il filtro
  • le opzioni per la seconda lista a quando il primo menu cambia

Al fine di cercare di lavorare con questa demo, ho aggiunto un controller per la singola riga. Questo mi ha dato l'accesso al modulo (name = rowform), ma non sono ancora in grado di impostare un orologio sulla proprietà "make". Non riesco nemmeno a trovare quale proprietà del modulo sta cambiando quando l'utente effettua una selezione.

Come si imposta un orologio sulla proprietà 'marca'?

controller Pagina

angular.module('app').controller("quoteBuckingRaterController", 
    function ($scope, $q, $filter, listService, transactionDataService) { 

     $scope.equipment = []; 
     $scope.makes = []; 
     $scope.models = []; 

     $scope.showModel = function(equip) { 
      if(equip.model) { 
       var selected = $filter('filter')($scope.models, {id: equip.model}); 
       return selected.length ? selected[0].name : 'Not set'; 
      } else { 
       return 'Not set'; 
      } 
     }; 

     $scope.showMake = function(equip) { 
      if (equip.model) { 
       var selected = $filter('filter')($scope.models, { id: equip.model }); 
       if (selected.length && selected.length > 0) { 
        if (equip.make != selected[0].make) 
         equip.make = selected[0].make; 
        return selected[0].make; 
       } 
       else { 
        return 'Not set'; 
       } 
      } else { 
       return 'Not set'; 
      } 
     }; 

     $scope.checkName = function (data, id) { 
      if (!data) { 
       return "Description is required"; 
      } 
     }; 

     $scope.checkModel = function (data, id) { 
      if (!data) { 
       return "Model is required"; 
      } 
     }; 

     $scope.saveEquipment = function (data, id) { 
      $scope.inserted = null; 
     }; 

     $scope.cancelRowEdit = function (data, id) { 
      $scope.inserted = null; 
     }; 

     $scope.removeEquipment = function(index) { 
      $scope.equipment.splice(index, 1); 
     }; 

     $scope.addEquipment = function() { 
      $scope.inserted = { 
       id: $scope.equipment.length+1, 
       name: '', 
       make: null, 
       model: null 
      }; 
      $scope.equipment.push($scope.inserted); 
     }; 

     $scope.filterModels = function (make) { 
      $scope.models = _.where($scope.allModels, function(item) { 
       return item.make == make; 
      }); 
     }; 

     //called by another process when page loads 
     $scope.initialize = function (loaded) { 
      return $q(function (resolve, reject) { 
       if (!loaded) { 
        listService.getEquipmentModels().then(function (data) { 
         $scope.allModels = data; 
         $scope.models = data; 

         //uses underscore.js 
         $scope.makes = _.chain(data) 
             .map(function (item) { 
              var m = { 
               id: item.make, 
               name: item.make 
              }; 
              return m; 
             }) 
             .uniq() 
             .value();        
         resolve(); 
        }); 
       } 
      }); 
     } 
    }); 

controller Row

angular.module('app').controller("editRowController", 
function ($scope) { 
    $scope.testClick = function() { 
     alert('button clicked'); 
    }; 

    $scope.make = null; 

    $scope.$watch('make', function() { 
     alert('how do I tell when the make has been changed?'); 
     this.$parent.$parent.filterModels(make.id); 
    }); 
}); 

HTML

<div> 
    <div class="col-md-12" style="margin-bottom: 3px"> 
     <div class="col-md-4 col-md-offset-1" style="padding-top: 6px; padding-left: 0px"><label>Equipment</label></div> 
     <div class="col-md-offset-10"> 
      <button class="btn btn-primary btn-sm" ng-click="addEquipment()">Add row</button> 
     </div> 
    </div> 
    <div class="col-md-10 col-md-offset-1">  
     <table class="table table-bordered table-hover table-condensed"> 
      <tr style="font-weight: bold; background-color: lightblue"> 
       <td style="width:35%">Name</td> 
       <td style="width:20%">Make</td> 
       <td style="width:20%">Model</td> 
       <td style="width:25%">Edit</td> 
      </tr> 
      <tr ng-repeat="equip in equipment" ng-controller="editRowController"> 
       <td> 
        <!-- editable equip name (text with validation) --> 
        <span editable-text="equip.name" e-name="name" e-form="rowform" onbeforesave="checkName($data, equip.id)" e-required> 
         {{ equip.name || 'empty' }} 
        </span> 
       </td> 
       <td> 
        <!-- editable make (select-local) --> 
        <span editable-select="equip.make" e-name="make" e-form="rowform" e-ng-options="s.value as s.name for s in makes"> 
         {{ showMake(equip) }} 
        </span> 
       </td> 
       <td> 
        <!-- editable model (select-remote) --> 
        <span editable-select="equip.model" e-name="model" e-form="rowform" e-ng-options="g.id as g.name for g in models" onbeforesave="checkModel($data, equip.id)" e-required> 
         {{ showModel(equip) }} 
        </span> 
        <button type="button" ng-disabled="rowform.$waiting" ng-click="testClick()" class="btn btn-default"> 
         test 
        </button> 
       </td> 
       <td style="white-space: nowrap"> 
        <!-- form --> 
        <form editable-form name="rowform" onbeforesave="saveEquipment($data, equip.id)" ng-show="rowform.$visible" class="form-buttons form-inline" shown="inserted == equip"> 
         <button type="submit" ng-disabled="rowform.$waiting" class="btn btn-primary"> 
          save 
         </button> 
         <button type="button" ng-disabled="rowform.$waiting" ng-click="rowform.$cancel()" class="btn btn-default"> 
          cancel 
         </button> 
        </form> 
        <div class="buttons" ng-show="!rowform.$visible"> 
         <button class="btn btn-primary" ng-click="rowform.$show()">edit</button> 
         <button class="btn btn-danger" ng-click="removeEquipment($index)">del</button> 
        </div> 
       </td> 
      </tr> 
     </table> 
    </div> 
</div> 
+0

Un jsfiddle di lavoro potrebbe aiutare qui. –

risposta

5

ng-repeat creates a child scope for each row (per ogni equipment). L'ambito di EditRowController è quindi un childScope del genitore quoteBuckingRaterController.

Questo childScope contiene:

  • tutte le proprietà del campo di applicazione principale (es equipment, makes, models)
  • proprietà equip con un valore della matrice equipment, fornito da NG-ripetere
  • qualsiasi proprietà di scope aggiuntiva definita all'interno del blocco ng-repeat, ad es rowform

Pertanto si sono in grado di accedere a queste proprietà nella childController editRowController utilizzando la variabile portata $, per es .:

$scope.equip.make 
$scope.equipment 

e all'interno dell'elemento ng-repeat nel file HTML utilizzando un angular expression, e.g:

{{equip.make}} 
{{equipment}} 

Ora per $scope.$watch: Se si fornisce una stringa come primo argomento, questo è un'espressione angolare come nel file html, ma senza parentesi {{}} circostante. Esempio per equip.make:

$scope.$watch('equip.make', function (value) { 
    console.log('equip.make value (on save): ' + value); 
}); 

Tuttavia, gli aggiornamenti angolare xeditable il valore di equip.make solo quando l'utente salva la riga. Se si desidera guardare l'input dell'utente dal vivo, è necessario utilizzare la proprietà $ dati nell'oggetto rowform, forniti da angolare xeditable:

$scope.$watch('rowform.$data.make', function (value) { 
    console.log('equip.make value (live): ' + value); 
}, true); 

È anche possibile utilizzare ng-cambio:

<span editable-select="equip.make" e-name="make" e-ng-change="onMakeValueChange($data)" e-form="rowform" e-ng-options="s.value as s.name for s in makes"> 

JS:

$scope.onMakeValueChange = function(newValue) { 
    console.log('equip.make value onChange: ' + newValue); 
} 

Questo dovrebbe risolvere la vostra prima domanda: come guardare la proprietà make.

La seconda domanda, come rilevare quando la riga è modificabile e quando non lo è, può essere risolta utilizzando gli attributi onshow/onhide nel modulo o guardando la proprietà $ visible dell'oggetto rowform nell'ambito come documented in the angular-xeditable reference

<form editable-form name="rowform" onshow="setEditable(true)" onhide="setEditable(false)"> 

$scope.setEditable = function(value) { 
     console.log('is editable? ' + value); 
}; 

// or 
$scope.$watch('rowform.$visible', function(value) { 
    console.log('is editable? ' + value); 
}); 

si potrebbe chiedere perché l'oggetto rowform è nel childScope corrente. Viene creato dal tag <form>. See the Angular Reference about the built-in form directive:

Direttiva che istanzia FormController.

Se è specificato l'attributo nome, il controllore modulo viene pubblicato sulla ambito corrente sotto questo nome.

Un frammento di lavoro con il codice di esempio:

angular.module('app', ["xeditable"]); 
 

 
angular.module('app').controller("editRowController", function ($scope) { 
 
    $scope.testClick = function() { 
 
     alert('button clicked'); 
 
    }; 
 

 
    $scope.$watch('equip.make', function (value) { 
 
     console.log('equip.make value (after save): ' + value); 
 
    }); 
 
    
 
    $scope.$watch('rowform.$data.make', function (value) { 
 
     console.log('equip.make value (live): ' + value); 
 
    }, true); 
 
    
 
    // detect if row is editable by using onshow/onhide on form element 
 
    $scope.setEditable = function(value) { 
 
     console.log('is equip id ' + $scope.equip.id + ' editable? [using onshow/onhide] ' + value); 
 
    }; 
 
    
 
    // detect if row is editable by using a watcher on the form property $visible 
 
    $scope.$watch('rowform.$visible', function(value) { 
 
     console.log('is equip id ' + $scope.equip.id + ' editable [by watching form property]? ' + value); 
 
    }); 
 
}); 
 

 

 
angular.module('app').controller("quoteBuckingRaterController", function ($scope, $filter) { 
 
    $scope.equipment = []; 
 
    $scope.makes = [{value: 1, name: 'Horst'}, {value: 2, name: 'Fritz'}]; 
 
    $scope.models = [{id: 1, name: 'PC', make: 1}]; 
 

 
    $scope.showModel = function(equip) { 
 
     if(equip.model) { 
 
      var selected = $filter('filter')($scope.models, {id: equip.model}); 
 
      return selected.length ? selected[0].name : 'Not set'; 
 
     } else { 
 
      return 'Not set'; 
 
     } 
 
    }; 
 

 
    $scope.showMake = function(equip) { 
 
     if (equip.model) { 
 
      var selected = $filter('filter')($scope.models, { id: equip.model }); 
 
      if (selected.length && selected.length > 0) { 
 
       if (equip.make != selected[0].make) 
 
        equip.make = selected[0].make; 
 
       return selected[0].make; 
 
      } 
 
      else { 
 
       return 'Not set'; 
 
      } 
 
     } else { 
 
      return 'Not set'; 
 
     } 
 
    }; 
 

 
    $scope.checkName = function (data, id) { 
 
     if (!data) { 
 
      return "Description is required"; 
 
     } 
 
    }; 
 

 
    $scope.checkModel = function (data, id) { 
 
     if (!data) { 
 
      return "Model is required"; 
 
     } 
 
    }; 
 

 
    $scope.saveEquipment = function (data, id) { 
 
     $scope.inserted = null; 
 
    }; 
 

 
    $scope.cancelRowEdit = function (data, id) { 
 
     $scope.inserted = null; 
 
    }; 
 

 
    $scope.removeEquipment = function(index) { 
 
     $scope.equipment.splice(index, 1); 
 
    }; 
 

 
    $scope.addEquipment = function() { 
 
     $scope.inserted = { 
 
      id: $scope.equipment.length+1, 
 
      name: '', 
 
      make: null, 
 
      model: null 
 
     }; 
 
     $scope.equipment.push($scope.inserted); 
 
    }; 
 
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-xeditable/0.1.9/js/xeditable.js"></script> 
 
<link href="https://cdnjs.cloudflare.com/ajax/libs/angular-xeditable/0.1.9/css/xeditable.css" rel="stylesheet"/> 
 
<link href="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet"/> 
 
<div ng-app="app" ng-controller="quoteBuckingRaterController"> 
 
    <div class="col-md-12" style="margin-bottom: 3px"> 
 
     <div class="col-md-4 col-md-offset-1" style="padding-top: 6px; padding-left: 0px"><label>Equipment</label></div> 
 
     <div class="col-md-offset-10"> 
 
      <button class="btn btn-primary btn-sm" ng-click="addEquipment()">Add row</button> 
 
     </div> 
 
    </div> 
 
    <div class="col-md-10 col-md-offset-1">  
 
     <table class="table table-bordered table-hover table-condensed"> 
 
      <tr style="font-weight: bold; background-color: lightblue"> 
 
       <td style="width:35%">Name</td> 
 
       <td style="width:20%">Make</td> 
 
       <td style="width:20%">Model</td> 
 
       <td style="width:25%">Edit</td> 
 
      </tr> 
 
      <tr ng-repeat="equip in equipment" ng-controller="editRowController"> 
 
       <td> 
 
        <!-- editable equip name (text with validation) --> 
 
        <span editable-text="equip.name" e-name="name" e-form="rowform" onbeforesave="checkName($data, equip.id)" e-required> 
 
         {{ equip.name || 'empty' }} 
 
        </span> 
 
       </td> 
 
       <td> 
 
        <!-- editable make (select-local) --> 
 
        <span editable-select="equip.make" e-name="make" e-form="rowform" e-ng-options="s.value as s.name for s in makes"> 
 
         {{ showMake(equip) }} 
 
        </span> 
 
       </td> 
 
       <td> 
 
        <!-- editable model (select-remote) --> 
 
        <span editable-select="equip.model" e-name="model" e-form="rowform" e-ng-options="g.id as g.name for g in models" onbeforesave="checkModel($data, equip.id)" e-required> 
 
         {{ showModel(equip) }} 
 
        </span> 
 
        <button type="button" ng-disabled="rowform.$waiting" ng-click="testClick()" class="btn btn-default"> 
 
         test 
 
        </button> 
 
       </td> 
 
       <td style="white-space: nowrap"> 
 
        <!-- form --> 
 
        <form editable-form name="rowform" onbeforesave="saveEquipment($data, equip.id)" ng-show="rowform.$visible" class="form-buttons form-inline" shown="inserted == equip" onshow="setEditable(true)" onhide="setEditable(false)"> 
 
         <button type="submit" ng-disabled="rowform.$waiting" class="btn btn-primary"> 
 
          save 
 
         </button> 
 
         <button type="button" ng-disabled="rowform.$waiting" ng-click="rowform.$cancel()" class="btn btn-default"> 
 
          cancel 
 
         </button> 
 
        </form> 
 
        <div class="buttons" ng-show="!rowform.$visible"> 
 
         <button class="btn btn-primary" ng-click="rowform.$show()">edit</button> 
 
         <button class="btn btn-danger" ng-click="removeEquipment($index)">del</button> 
 
        </div> 
 
       </td> 
 
      </tr> 
 
     </table> 
 
    </div> 
 
</div>

+0

Suggerimento molto bello sul modificabile, ma l'orologio non funziona quando si è in modalità modifica. controlla https://jsfiddle.net/Steve5877/32kzsvve/ Il codice che hai inviato con alcuni modelli extra e un tentativo di filtrare i modelli quando viene selezionato make. Ma non attiva l'orologio quando apporta modifiche durante la modifica. –

+0

Ho intenzione di assegnare la taglia perché il sistema non mi dà molta scelta. Non è possibile estendere la taglia, anche se nessuno l'ha guardato fino all'ultimo minuto. Questa risposta NON è completa e NON funziona ancora, ma è la più vicina e mostra il massimo sforzo. Se non lo premo, ottiene comunque metà credito (a meno che non lo downgrade) e non ottengo nulla. Spero che Felix aggiornerà la sua risposta quando vedrà il problema che sto ancora avendo. –

+0

@SteveWash Ho aggiornato la mia risposta e il tuo jsFiddle: https://jsfiddle.net/32kzsvve/1/ –

2

Se si vuole semplicemente $watch proprietà make di equipment, prova a cambiare a:

$scope.$watch('equipment.make', function(){(...)}) 
1

Si potrebbe scrivere la propria direttiva per questo.

Il vantaggio principale è che le direttive hanno isolato portata e possono avere il loro controllore.

vedere the directive documentation per sapere se è per voi.