I am displaying some data in a web app that I am getting from a SQL database using a http service. I want to be able to modify the information of that data on the same table where the data is shown. I am using angularjs and I am using the directives ng-show and ng-hide on the table. Here I show the part of the code I am talking about.

    <table>
    <tr>
        <td><font size = 4>Servicio:    </font> </td>
        <td>  </td>
        <td>
            <select class="col-sm-12" name="repeatSelect" id="repeatSelect" ng-model="currentItem.ServicioId">
                <option ng-repeat="option in items.Servicio" value="{{option.Id}}"> {{option.Nombre}}</option>
            </select>
        </td>
    </tr>
</table>


<h4>Cliente:  {{getNameC(currentItem.ServicioId)}}</h4>
<br />
<button class="btn btn-primary" ng-click="editOrCreate()">Nuevo</button>
<button class="btn btn-primary" ng-click="list()">Actualizar</button>
     <table class="table table-striped table-bordered">
        <thead>
            <tr>
                <th>Cantidad</th>
                <th>Tipo Concepto</th>
                <th>Descripción</th>
                <th>Precio Unitario</th>
                <th></th>
            </tr>
        </thead>
        <tbody>             

            <tr ng-repeat="item in itemsSC">
                <td>
                    <div ng-hide="editingData[item.Id]">{{item.Cantidad}}</div>
                    <div ng-show="editingData[item.Id]"><input ng-model="currentItem.Cantidad" /></div>
                </td>
                <td>
                    <div ng-hide="editingData[item.Id]">{{getName(item.ServicioConceptoTipoId)}}</div>
                    <div ng-show="editingData[item.Id]">
                       <select name="repeatSelect" id="repeatSelect" ng-model="currentItem.ServicioConceptoTipoId">
                            <option ng-repeat="option in items.ServicioConceptoTipo" value="{{option.Id}}"> {{option.Nombre}}</option>
                        </select>
                    </div>
                </td>
                <td>
                    <div ng-hide="editingData[item.Id]">{{item.Descripcion}}</div>
                    <div ng-show="editingData[item.Id]"><input type="text" ng-model="currentItem.Descripcion" /></div>
                </td>
                <td>
                    <div ng-hide="editingData[item.Id]">{{item.PrecioUnitario}}</div>
                    <div ng-show="editingData[item.Id]"><input ng-model="currentItem.PrecioUnitario" /></div>
                </td>
                <td>
                    <button class="btn btn-xs btn-primary" ng-hide="editingData[item.Id]" ng-click="editOrCreate(item)">Modificar</button>
                    <button class="btn btn-xs btn-primary" ng-show="editingData[item.Id]" ng-click="saveEdit(currentItem,0)">Actualizar</button>
                    <button class="btn btn-xs btn-primary" ng-hide="viewField" ng-click="delete(item)">Eliminar</button>
                </td>
            </tr>
        </tbody>
        <tfoot id="total">
            <tr>
                <td colspan="3" class="text-right">Total:</td>
                <td class="text-right">
                    {{total(currentItem.ServicioId) | currency}}
                </td>
            </tr>
        </tfoot>
    </table>

On my controller I am using object arrays to get the information from the databases and I am using a mirror array to keep the boolean values of the data shown on the table, so depending on the boolean value the tables shows the data or get an input for the user to modify the data.

I get the mirror array once I know the service and client related to the data I want to show and which is possible to be modified.

However, when I click on the button to modify the status of the ng-hide or ng-show object named editingData, the controllers modifies it, but the $digest run all the other functions related to the bindings of the view and returns the bool object array to its inital values.

I haven´t been able to find away to go around this normal working way of the $digest and $watches so my $editingData object is not modified to its initial values. Here I show the code of the controller related to this.

angular.module("App")

 .controller("ConceptoCtrl", function ($scope, $http, $resource, serviciosConceptoFactory, serviciosConceptoTipoFactory, serviciosFactory, clientesFactory) {

  $scope.list = function () {
       $scope.items = serviciosConceptoFactory.query();

       $scope.itemsT = serviciosConceptoTipoFactory.query();
       $scope.items.ServicioConceptoTipo = $scope.itemsT;

       $scope.itemsS = serviciosFactory.query();
       $scope.items.Servicio = $scope.itemsS;

       $scope.itemsC = clientesFactory.query();
       $scope.itemsS.Cliente = $scope.itemsC;
    }

    //some other functions

     $scope.editingData = {};  

     $scope.getitemsSC = function (item) {
        $scope.itemsSC = [];
        for (var j = 0; j < $scope.items.length; j++) {
           if ($scope.items[j].ServicioId == item) {
               newitem = $scope.items[j];
               $scope.itemsSC.push(newitem);
           }
        }             

       for (var i = 0; i < $scope.itemsSC.length; i++) {
           $scope.editingData[$scope.itemsSC[i].Id] = false; 
       }            
    }


    $scope.editOrCreate = function (item) {       
        $scope.currentItem = item;    
        $scope.editingData[item.Id] = true;    
    }

   $scope.list();

  });

The {{getNameC(currentItem.ServicioId}} function shown on the html file is the one that calls the $scope.getItemsSC(item) function once it knows the services and client related to the data that will be shown and it is this function the one that initializes the boolean values for the $scope.editingData mirror array depending on the Id of the item.

The $scope.editOrCreate(item) function is the one that changes the boolean object of the specified item so that the view shows the input element for the user instead of the data. However, $digest re-runs the $scope.getItemsSC(item) function because the $watches were modified, and that´s what I want to avoid, because in this case the input elements are never shown.

I thank in advance any help provided

1

There are 1 answers

3
georgeawg On

Instead of using the HTML to call functions when data is a available, use the $promise property attached to the resources.

$scope.list = function () {
   $scope.items = serviciosConceptoFactory.query();

   $scope.itemsT = serviciosConceptoTipoFactory.query();
   $scope.items.ServicioConceptoTipo = $scope.itemsT;

   $scope.itemsS = serviciosFactory.query();
   $scope.items.Servicio = $scope.itemsS;

   $scope.itemsC = clientesFactory.query();
   $scope.itemsS.Cliente = $scope.itemsC;

   var promiseArray = [$scope.items.$promise,
                       $scope.itemsT.$promise,
                       $scope.itemsS.$promise,
                       $scope.itemsC.$promise
                      ];

   $q.all(promiseArray).then(function(resultsArray) {
        var items = resultsArray[0];
        var itemsT = resultsArray[1];
        var itemsS = resultsArray[2];
        var itemsC = resultsAttay[3];

        //create mirror array here
        //create editingData array here
   });
};

By using the .then method of the promises, the processing of the data can be delayed until it arrives from the server. This way there is no need for the HTML to call functions.