How To Update Page After Calling $http.put service in Directive Using AngularJS/Web API/Angular-ui-router

jaz*_*Box 8 asp.net-web-api angularjs angularjs-directive angularjs-scope angular-bootstrap

We are new to AngularJS but are working on an AngularJS/Web API application that updates a data model from an AngularJS Bootstrap popover/directive.

We've successfully updated the database from the directive/popover, however are having trouble figuring out how to refresh the data on the page with the updated data without reloading the page.

Main Page CSHTML:

<div ng-app="FFPA" ng-controller="myCtrl">
   <div svg-floorplan="dataset"></div>
</div>
Run Code Online (Sandbox Code Playgroud)

Popover HTML:

<div>
   <div>
      ID: {{ person.Id }}<br />
      Name: {{ person.fullName }}<br />
      Current Cube/Office: {{ person.seatId }}
      <br />
      Dept: {{ person.deptId }}
      <br />
      Job Desc: {{ person.jobDesc}}
      <br />
      Phone:{{ person.phone}}
      <br />
      <!--<input type="button" value="Click Me" ng-click="changeName()">-->
   </div>
   <div class="hiddenDiv" ng-hide="toggle">
      <div class="form-group">
         <label for="floor">Floor</label>
         <input id="floor" ng-model="person.floor" type="text" ng-trim="true"  class="form-control" />
      </div>
      <div class="form-group">
         <label for="section">Section</label>
         <input id="section" ng-model="person.section" ng-trim="true" type="text" class="form-control" />
      </div>
      <div class="form-group">
         <label for="offCubeNum">offCubeNum</label>
         <input id="offCubeNum" ng-model="person.offCubeNum" ng-trim="true" type="text" class="form-control" />
      </div>
      <div class="form-group">
         <label for="cbCube">Cubicle?</label>
         <input id="cbCube" ng-model="person.cbCube" type="checkbox" size="1" class="checkbox" />
      </div>
   </div>
   <div ng-hide="buttonToggle">
      <input type="button" value="Move" class="btn btn-success" ng-click="moveEmp()">
      <input type="button" value="Term" class="btn btn-danger" ng-click="changeName()">
   </div>
   <div ng-hide="submitToggle">
      <input type="button" value="Submit" class="btn btn-success" ng-click="submitMove()">
      <input type="button" value="Cancel" class="btn btn-warning" ng-click="cancel()">
   </div>
</div>
Run Code Online (Sandbox Code Playgroud)

The main page initially gets data from a service in the angular controller:

var app = angular.module('FFPA', ['ngAnimate', 'ngSanitize', 'ui.bootstrap', 'ui.router']);
    app.controller('myCtrl', function ($scope, dataService) {
    $scope.test = 'test';
        dataService.getData().then(function (data) {
            //The reduce() method reduces the array to a single value.
            $scope.dataset = data.reduce(function (obj, item) {
                obj[item.seatId.trim()] = item;
                item.fullName = item.fName + ' ' + item.lName;
                item.deptId = item.deptId;
                item.jobDesc = item.jobDesc;
                item.phone = item.phone;

                return obj;

            }, {});
        });
    });
Run Code Online (Sandbox Code Playgroud)

Get Data Service:

    angular.module('FFPA').service('dataService', function ($http) {
    this.getData = function () {
        //web api call
        return $http.get("api/Controller/GetData).then(
          function (response) {
              return response.data;
          }, function () {
              return { err: "could not get data" };
          }
        );
    }
});
Run Code Online (Sandbox Code Playgroud)

The Update Service is called from the Popover Directive.

Update Service:

    angular.module('FFPA').service('updateService', function ($http) {
    this.putData = function (oc) {

        //web api call
        return $http.put("api/Controller/PutUpdateData", oc).then(
          function (response) {

              return response.data;
          }, function () {
              return { err: "could not update data" };
          }
        );
    }
});
Run Code Online (Sandbox Code Playgroud)

Here is a snippet from our Popover directive where the update occurs and where we thought we could refresh the scope, and the data for the page:

updateService.putData(data).then(function (response) {
   if (response == false)
    alert("Move Failed!");
   else {
    alert("Move Succeeded.");
    //$window.location.reload() causes a page reload..not desirable
    //$window.location.reload();
     $state.reload();
}
});
Run Code Online (Sandbox Code Playgroud)

We tried a $state.reload(); in the popover directive just after updateService.putData(data), however this caused -> Error: Cannot transition to abstract state '[object Object]' error.

Here is the full Popover Directive:

angular.module('FFPA').directive('svgFloorplanPopover', ['$compile', 'updateService', 'vacancyService', 'addService', 'terminateService', '$window', '$state', function ($compile, updateService, vacancyService, addService, terminateService, $window, $state) {
return {
    restrict: 'A',
    scope: {
        'person': '=svgFloorplanPopover',
         //UPDATE 8-MAY-2017
         onDataUpdate: '&'
    },
    link: function (scope, element, attrs) {
        scope.moveToggle   = true;               //hide move toggle
        scope.addToggle    = true;                //hide add toggle
        scope.submitToggle = true;             //hide submit toggle


        scope.$watch("person", function () {
            if (scope.person) {
                if (scope.person.vacant == true) {
                    scope.addToggle         = false;  //show add button
                    scope.empInfoToggle     = true;   //hide emp info
                }
                else
                    scope.moveToggle = false; //show move
            }
        });

        //add employee---------------------------------------------------------
        scope.addEmp = function () {
            scope.addToggle = scope.addToggle === false ? true : false;

            scope.buttonToggle = true;
            scope.submitToggle = false;

            var data = {
                deptId: scope.person.deptId,
                divisionId: scope.person.divisionId,
                empId: scope.person.empId,
                floor: scope.person.floor,
                fName: scope.person.fName,
                lName: scope.person.lName,

                jobDesc: scope.person.jobDesc,
                officeCode: scope.person.officeCode,
                phone: scope.person.phone,
                section: scope.person.section,
                seat: scope.person.seat,
                seatId: scope.person.seatId,
                seatTypeId: scope.person.seatTypeId,
                vacant: scope.person.vacant
            };


            //call to update/move the employee 
            //updateService.putData(scope.person).then(function () {
            addService.putData(data).then(function (response) {
                if (response == false)
                    alert("Create Failed!");
                else {
                    alert("Create Succeeded.");
                      //UPDATE 8-MAY-2017
                      $scope.onDataUpdate({ person: $scope.person, moreData: $scope.moreData });
                    //$window.location.reload();
                    //$route.reload();
                    //scope.toggle = false;
                }
            });
        }


        //cancel function---------------------------------------------------------
        scope.cancel = function () {}

        //Term emp---------------------------------------------------------
        scope.termEmp = function () {
            var data = {
                seatId: scope.person.seatId,
                floor: scope.person.floor
            };
            terminateService.putData(data).then(function (response) {
                if (response == false)
                    alert("Term Failed!");
                else {
                    alert("Term Succeeded.");
                    $window.location.reload();
                    //$route.reload();
                    //scope.toggle = false;
                }

            });
        }


        //move employee---------------------------------------------------------
        scope.moveEmp = function () {
            scope.toggle = scope.toggle === false ? true : false;
            scope.buttonToggle = true;
            scope.submitToggle = false;
            if (scope.person && scope.person.fullName.indexOf('changed') === -1) {
                //scope.person.fullName += ' move?';
            }

            //Json object to send to controller to check for vacancy
            var data = {
                floor: scope.person.floor,
                section: scope.person.section,
                seat: scope.person.offCubeNum
            };

            //can't send object via $http.get (?) stringigy json and cast to Office object in controller.
            var json = JSON.stringify(data);

            //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
            //CHECK VACANCY service call
            //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
            vacancyService.getData(json)
                .then(function (response) {
                if (response == false)
                    alert("cube/office occupied");
                else{

                    //+++++++++++++++++++++++++++++++++++++++++++
                    //UPDATE service call
                    //+++++++++++++++++++++++++++++++++++++++++++
                    //CONSTS
                    var CONSTFLOORPREFIX    = "f";
                    var CONSTSEAT           = "s";
                    var CONSTC              = "c"

                    var floor   = scope.person.floor;
                    var section = scope.person.section;

                    var offCube = scope.person.offCubeNum;
                    scope.person.oldSeatId = scope.person.seatId;

                    var newOfficeId = CONSTFLOORPREFIX + floor + CONSTSEAT;          //f3s 

                    //IF CUBE
                    if (scope.person.cbCube) {
                        var trimSection = section.trim();
                        newOfficeId += trimSection + CONSTC;                        //f3s313c
                        var trimOffCube = offCube.trim();
                        newOfficeId += trimOffCube;
                    }
                    else { 
                        newOfficeId += 0 + CONSTC + section;                                  //f3s0c
                    }



                    scope.person.seatId = newOfficeId;

                    //Json object to send to controller to check for vacancy
                    var data = {
                        Id: scope.person.Id,
                        seatId: scope.person.seatId,
                        oldSeatId: scope.person.oldSeatId,
                        empId: scope.person.empId,
                        lName: scope.person.lName,
                        fName: scope.person.fName,
                        refacName: scope.person.refacName,
                        deptId: scope.person.deptId,
                        divisionId: scope.person.divisionId,
                        jobDesc: scope.person.jobDesc,
                        seatTypeId: scope.person.seatTypeId,
                        officeCode: scope.person.officeCode,
                        phone: scope.person.phone,
                        floor: scope.person.floor,
                        section: scope.person.section,
                        seat: scope.person.seat,
                        vacant: scope.person.vacant
                    };


                    //call to update/move the employee 
                    //updateService.putData(scope.person).then(function () {
                    updateService.putData(data).then(function (response) {
                        if (response == false)
                            alert("Move Failed!");
                        else {
                            alert("Move Succeeded.");
                            //$window.location.reload();
                            $state.reload();
                            //$route.reload();
                            //scope.toggle = false;
                        }

                    });
                }//end else
            });
        }

        if (element[0].querySelector('text') != null){
            scope.htmlPopover = './HTML/popoverTemplate.html';
            element[0].setAttribute('uib-popover-template', "htmlPopover");
            element[0].setAttribute('popover-append-to-body', 'true');
            element[0].setAttribute('popover-trigger', "'click'");
            //element[0].setAttribute('popover-trigger', "'mouseenter'");
            element[0].setAttribute('popover-placement', 'right');
            element[0].removeAttribute('svg-floorplan-popover');
            $compile(element)(scope);
        }
    }
}
}]);
Run Code Online (Sandbox Code Playgroud)

UPDATED: 8-MAY-2017 Originally there is one additional data service and a directive that we left out of this post since it may be considered not essential information, however recently added since it may be needed.


SVG Load Directive:

angular.module('FFPA').directive('svgFloorplan', ['$compile', function ($compile) {
return {
    restrict: 'A',  //restrict attributes
    templateUrl: './SVG/HQ3RD-FLOOR3v10.svg',
    scope: {
        'dataset': '=svgFloorplan'
    },
    link: {
        pre: function (scope, element, attrs) {
            //filter groups based on a cube/office id
            var groups = element[0].querySelectorAll("g[id^='f3']");
            //groups.style("pointer-events", "all");
            scope.changeName = function (groupId) {
                if (scope.dataset[groupId] && scope.dataset[groupId].lastName.indexOf('changed') === -1) {
                    scope.dataset[groupId].lastName += ' changed';
                }
            }

            groups.forEach(function (group) {
                var groupId = group.getAttribute('id');
                if (groupId) {
                    //set vacancy colors on vacant cubes
                    scope.$watch("dataset", function () {
                        if (scope.dataset) {
                            if (typeof scope.dataset[groupId] !== "undefined") {

                                //vacant cubes and offices hover
                                if (scope.dataset[groupId].vacant == true) {
                                    //seat type id 1 = cube
                                    if (scope.dataset[groupId].seatTypeId == 1){
                                        d3.select(group).select("rect").style("fill", "#99ff33").style("opacity", 0.4)
                                            .style("pointer-events", "all")
                                            .on('mouseover', function () {
                                             d3.select(this).style('opacity', 0.9);
                                         })
                                        .on('mouseout', function () {
                                            d3.select(this).style('opacity', 0.4);
                                        })
                                    }
                                    //vacant office
                                    else {
                                        d3.select(group).select("path").style("stroke", "#ffffff").style("opacity", 1.0);
                                        d3.select(group).select("path").style("fill", "#99ff33").style("opacity", 0.4)
                                        .style("pointer-events", "all")
                                         .on('mouseover', function () {
                                             d3.select(this).style('opacity', 0.9);
                                         })
                                        .on('mouseout', function () {
                                            d3.select(this).style('opacity', 0.4);
                                        })
                                    }
                                }
                                else {                              //Occupied 
                                    //seat type id 1 = cube
                                    if (scope.dataset[groupId].seatTypeId == 1) {
                                        d3.select(group).select("rect").style("fill", "#30445d").style("opacity", 0.0)
                                         .style("pointer-events", "all")
                                         .on('mouseover', function () {
                                             d3.select(this).style('opacity', 1.0);
                                             d3.select(group).select('text').style("fill", "#FFFFFF");
                                         })
                                        .on('mouseout', function () {
                                            d3.select(this).style('opacity', 0.0);
                                            d3.select(group).select('text').style("fill", "#000000");
                                        })

                                        //TODO: cubes have rects and on the north side of the building wall, paths.
                                        d3.select(group).select("path").style("fill", "#30445d").style("opacity", 0.0)
                                            .style("pointer-events", "all")
                                            .on('mouseover', function () {
                                                d3.select(this).style('opacity', 1.0);
                                                d3.select(group).select('text').style("fill", "#FFFFFF");
                                            })
                                        .on('mouseout', function () {
                                            d3.select(this).style('opacity', 0.0);
                                            d3.select(group).select('text').style("fill", "#000000");
                                        })
                                    }
                                    //occupied office
                                    else {
                                        //d3.select(group).select("path").style("stroke", "#ffffff").style("opacity", 0.8);
                                        d3.select(group).select("path").style("fill", "#5A8CC9").style("opacity", 1.0)
                                         .style("pointer-events", "all")
                                         .on('mouseover', function () {
                                             //alert("office");
                                             d3.select(this).style("fill", "#2d4768").style('opacity', 1.0);
                                             d3.select(group).selectAll('text').style("fill", "#FFFFFF");
                                         })
                                        .on('mouseout', function () {
                                            d3.select(this).style("fill", "#5A8CC9").style('opacity', 1.0);
                                            d3.select(group).selectAll('text').style("fill", "#000000");
                                        })
                                    }
                                }//end occupied else
                            }
                        }
                    });
                     //UPDATE 8-MAY-2017->Implementation Question
                    scope.onDataUpdateInController = function (person, moreData) { };
                    var datasetBinding = "dataset['" + groupId + "']";
                    group.setAttribute('svg-floorplan-popover', datasetBinding);

                    //UPDATE 8-MAY-2017
                    //on-data-update corresponds to onDataUpdate item on svgFloorplanPopover's scope.
                    group.setAttribute('on-data-update', onDataUpdateInController);


                    $compile(group)(scope);
                }
            });
        }


    }
}
}]);
Run Code Online (Sandbox Code Playgroud)

Vacancy Service (check before update):

angular.module('FFPA').service('vacancyService', function ($http) {
...
}
Run Code Online (Sandbox Code Playgroud)

The main question is:

How can we have our application refresh our page with the updated data without reloading the page?

We used to be able to do this in UpdatePanels in ASP.Net webforms back in the day. I think they were partial postbacks/AJAX calls..

EDITED 2-AUG-2017

+++++++++++++++++++++++++++++++++++

虽然赏金是自动授予的,但我们仍然没有这个问题的答案.没有任何实现上下文,给出的答案是没有用的.

任何人都可以扩展给出的答案,让我们了解如何解决这个问题?

谢谢

小智 1

要刷新您的视图(不绑定接收到的数据),请使用以下问题的答案:

使用 ngRoute 模块 如何使用 AngularJS 重新加载或重新渲染整个页面

使用 ui-router 模块 重新加载当前状态 - 刷新数据

因此,我建议您将收到的数据分配给有界的 $scope 属性。

在您提供更新的 plnkr 后,我将添加一个完整的示例:)