范围变量的价值变化不会反映在我的字符串中



我的字符串下方:

"/root/get";

现在,我正在在上面的字符串中生成一个查询字符串,其中有1个范围变量,但是问题是当该变量更改的值时,新值并未自动在我的URL中进行更新。

您可以在下面的演示中看到我有2个按钮更新并检查。在更新中,我正在生成查询字符串和检查按钮,我正在更新示波器变量的值,但没有反映在我的URL中。

我没有得到为什么会发生这种情况。

当我单击检查按钮而无需拨打generateSqueryparameters方法时,预期输出方法:

/root/get?no=2

var app = angular.module("myApp", []);
        app.controller("myController", function ($scope) {
        
        $scope.no = 1;
        $scope.str = "/root/get";
     
        $scope.update = function (data) {
          $scope.str=generateQueryParameters($scope.str,
               "no",$scope.no);
               console.log($scope.str);
        };
           
            $scope.check = function () {
              $scope.no=2;
              console.log($scope.str);
            };
               
    function generateQueryParameters(url,name,value)
    {
        var re = new RegExp("([?&]" + name + "=)[^&]+", "");
        function add(sep) {
            url += sep + name + "=" + encodeURIComponent(value);
        }
        function change() {
            url = url.replace(re, "$1" + encodeURIComponent(value));
        }
        if (url.indexOf("?") === -1) {
            add("?");
        } else {
            if (re.test(url)) {
                change();
            } else {
                add("&");
            }
        }
        return url;
    }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myController">
    <input type="button" value="Update" ng-click="update()">
    <input type="button" value="Check" ng-click="check()">
</div>

更新:我知道$ scope.no的值何时会更改,所以我认为我不需要观察器,我不想再次致电generateParameters。为什么Angular不自动更新我的str中的值就像Angular Binding的工作方式一样?

让我们从代码中的问题开始。您可以通过函数生成请求字符串,该函数实际上仅在update函数

中称为
$scope.update = function(data) {
  $scope.str = generateQueryParameters($scope.str,
    "no", $scope.no);
  console.log($scope.str);
};

$scope.check = function() {
  $scope.no = 2;
  console.log($scope.str);
};

您更改check函数中的版本号,但没有再次调用该函数以更改$scope.str,因此$scope.str的值仍然相同。

您可以轻松地测试该片段中的以下步骤:

  1. 单击更新(V0)

  2. 单击检查(V0)

  3. ,但然后再次单击更新,您将看到它已更新(v2)

因此,在步骤2中,您实际上更改了版本,您根本不再生成要使用的str

因此,对于您的代码来说,简单的修复就是安排您的代码,以调用分配新str的功能,每次更改版本时:

$scope.update = function(data) {
  $scope.no = 1;
  $scope.str = generateQueryParameters($scope.str,
    "no", $scope.no);
  console.log($scope.str);
};

$scope.check = function() {
  $scope.no = 2;
  // here you need to call again your function for composing your URL and changing the value of str
  $scope.str = generateQueryParameters($scope.str,
    "no", $scope.no);
  console.log($scope.str);
};
function generateStringRequest() {
}

否则,您需要观看no版本参数,并在每次版本更改时自动刷新str值。但是,该解决方案意味着您将在每个调用API的控制器中都有一个观察器,并且所有参数始终在控制器内部进行硬编码:

$scope.$watch('no', function() {
    $scope.str = generateQueryParameters($scope.str, 'no', $scope.no);
});

即使此解决方案有效,实际上它很糟糕。管理呼叫的逻辑是在控制器内部,这是一个非常糟糕的做法(您应该考虑为此使用集中式服务)。

好多了,在AngularJS中,您可以使用自定义拦截器并在其中管理有关HTTP请求的所有操作。因此,您可以指定为HTTP请求的参数,即您要使用的API的版本。

这将保持您的代码清洁。此外,如果您想在将来更改一些请求,则可以简单地更改该请求参数。如果要更改所有请求,则可以在拦截器内部设置所有请求,以使version 1的所有请求将被version 2替换。

在这里,有关如何定义拦截器的示例代码:

angular.module('myApp').factory('MyHTTPFactory', MyHTTPFactory)
  .config(function($httpProvider) {
    // register the new interceptor in AngularJS
    $httpProvider.interceptors.push('MyHTTPFactory');
  });
MyHTTPFactory.$inject = [];
function MyHTTPFactory() {
  // this is the base URL of your rest requests, so this interceptor will be applied only to the requests directed to your service
  const MY_REST_URL = 'blablabla';
  // methods exposed by the service
  let factory = {
    request: request,
    requestError: requestError,
    response: response,
    responseError: responseError
  };
  return factory;
  // ============================================================

  function request(config) {
    if (config.url.includes(MY_REST_URL)) {
      let versionToUse = config.version;
      // here use a function for elaborating your query string, directly in the interecptor code
      config.url = elaborateQueryString();
    }
    return config;
  }
  function requestError(config) {
    return config;
  }
  function response(res) {
    return res;
  }
  function responseError(res) {
    return res;
  }
  // function for getting the query string you want to
  function elaborateQueryString() {
    // elaborate your requests
  }
}

然后,只需一如既往地执行HTTP请求,通过$http添加您要在请求中使用的版本作为参数:

// perform your request as usual simply specifying the new version parameter
let request = {
  url: `myserviceurl`,
  version: '2' // or whatever you qNR
};
$http(request);

因此,拦截器将在执行之前"嗅探"您的所有请求,它将正确构成版本和查询字符串,并且您的所有操作都在其中管理并集中。

就像最后一个提示一样,当定义诸如版本号之类的常数,其余服务的端点(无论如何)时,请使用angularjs constant并将其注入需要使用它们的位置。硬编码的字符串不是一个好习惯。

您可以使用新的 Controller作为语法轻松定义A property str(允许您直接绑定到控制器属性和方法)因此:

  Object.defineProperty(vm,
    "str", {
      get: function() {
        return vm.generateQueryParameters("/root/get","no", vm.no);
      },
      set: function(newValue) {
        // setter function
      },
      enumerable: true,
      configurable: true
  });

这意味着您每次您访问str的值,它会重新评估URL字符串。这使您的代码独立 $scope$watch更具前瞻性。

var app = angular.module("myApp", []);
app.controller("myController", function() {
  var vm = this;
  vm.no = 1;
  Object.defineProperty(vm,
    "str", {
      get: function() {
        return vm.generateQueryParameters("/root/get","no", vm.no);
      },
      set: function(newValue) {
        // setter function
      },
      enumerable: true,
      configurable: true
  });
  vm.update = function(data) {
    console.log(vm.str);
  };
  vm.check = function() {
    vm.no = 2;
    console.log(vm.str);
  };
  vm.generateQueryParameters = function(url, name, value) {
    var re = new RegExp("([?&]" + name + "=)[^&]+", "");
    function add(sep) {
      url += sep + name + "=" + encodeURIComponent(value);
    }
    function change() {
      url = url.replace(re, "$1" + encodeURIComponent(value));
    }
    if (url.indexOf("?") === -1) {
      add("?");
    } else {
      if (re.test(url)) {
        change();
      } else {
        add("&");
      }
    }
    return url;
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myController as ctrl">
  <input type="button" value="Update" ng-click="ctrl.update()">
  <input type="button" value="Check" ng-click="ctrl.check()">
</div>

对于以下对象(来自讨论):

[
  {
    "name": "Node-1",
    "isParent": true,
    "text" : [
       {
           "str" : "/root/get",
       },
       {
          "str" : "/root/get",
       }],
     "nodes": [
      {
        "name": "Node-1-1",
        "isParent": false,
         "text" : [
           {
             "str" : "/root/get",
           },
           {
             "str" : "/root/get",
           }],
           "nodes": [
           {
            "name": "Node-1-1-1",
            "isParent": false,
            "text" : [
            {
              "str" : "/root/get",
            },
            {
              "str" : "/root/get",
            }],
            "nodes": []
          }
        ]
      }
    ]
  }
]

我们可以扩展此方法 - 请参见下面的演示:

var app = angular.module("myApp", []);
app.controller("myController", function() {
  var vm = this;
  vm.no = 1;
  vm._records=[{"name":"Node-1","isParent":true,"text":[{"str":"/root/get",},{"str":"/root/get",}],"nodes":[{"name":"Node-1-1","isParent":false,"text":[{"str":"/root/get",},{"str":"/root/get",}],"nodes":[{"name":"Node-1-1-1","isParent":false,"text":[{"str":"/root/get",},{"str":"/root/get",}],"nodes":[]}]}]}];
  
  vm.setRecords = function(node, url) {
    node.text && node.text.forEach(function(e){
      e.str = url;
    });
    // recursively set url
    node.nodes && node.nodes.forEach(function(e){
      vm.setRecords(e, url);
    });
  }
  Object.defineProperty(vm,
    "records", {
      get: function() {
        let url = vm.generateQueryParameters("/root/get", "no", vm.no);
        vm._records.forEach(function(e){
          vm.setRecords(e, url);
        });
        return vm._records;
      },
      set: function(newValue) {
        // setter function
      },
      enumerable: true,
      configurable: true
    });
  vm.update = function(data) {
    console.log(vm.records);
  };
  vm.check = function() {
    vm.no = 2;
    console.log(vm.records);
  };
  vm.generateQueryParameters = function(url, name, value) {
    var re = new RegExp("([?&]" + name + "=)[^&]+", "");
    function add(sep) {
      url += sep + name + "=" + encodeURIComponent(value);
    }
    function change() {
      url = url.replace(re, "$1" + encodeURIComponent(value));
    }
    if (url.indexOf("?") === -1) {
      add("?");
    } else {
      if (re.test(url)) {
        change();
      } else {
        add("&");
      }
    }
    return url;
  }
});
.as-console-wrapper{top:25px;max-height:calc(100% - 25px)!important;}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myController as ctrl">
  <input type="button" value="Update" ng-click="ctrl.update()">
  <input type="button" value="Check" ng-click="ctrl.check()">
</div>

您需要为no添加Watcher,该Watcher称为generateQueryParameters,并更改$scope.str

的值

var app = angular.module("myApp", []);
        app.controller("myController", function ($scope) {
        
        $scope.no = 1;
        $scope.str = "/root/get";
     
        $scope.check = function () {
               console.log($scope.str);
        };
        
        $scope.$watch('no', function() {
          $scope.str = generateQueryParameters($scope.str,
               "no",$scope.no);
        });
           
            $scope.update = function (data) {
              $scope.no=2;
            };
               
    function generateQueryParameters(url,name,value)
    {
        var re = new RegExp("([?&]" + name + "=)[^&]+", "");
        function add(sep) {
            url += sep + name + "=" + encodeURIComponent(value);
        }
        function change() {
            url = url.replace(re, "$1" + encodeURIComponent(value));
        }
        if (url.indexOf("?") === -1) {
            add("?");
        } else {
            if (re.test(url)) {
                change();
            } else {
                add("&");
            }
        }
        return url;
    }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myController">
    <input type="button" value="Update" ng-click="update()">
    <input type="button" value="Check" ng-click="check()">
</div>

首次更新,然后检查

您需要在检查方法中再次调用GenerateSqueryParameters方法。

$scope.check = function () {
              $scope.no=2;
              $scope.str=generateQueryParameters($scope.str,
               "no",$scope.no);
              console.log($scope.str);
            };

尝试一下,问题是在JavaScript原始值中以值而不是参考。

var app = angular.module("myApp", []);
    app.controller("myController", function ($scope) {
    $scope.testObject = {
       no: 1,
       str: "/root/get"
    };
    $scope.update = function (data) {
      $scope.str=generateQueryParameters($scope.testObject,
           "no");
           console.log($scope.testObject);
    };

        $scope.check = function () {
          $scope.testObject.no=2;
          console.log($scope.testObject.str);
        };
function generateQueryParameters(urlAndValue, name)
{
    var re = new RegExp("([?&]" + name + "=)[^&]+", "");
    function add(sep) {
        urlAndValue.str += sep + name + "=" + encodeURIComponent(urlAndValue.no);
    }
    function change() {
        urlAndValue.str = urlAndValue.str.replace(re, "$1" + encodeURIComponent(urlAndValue.no));
    }
    if (urlAndValue.str.indexOf("?") === -1) {
        add("?");
    } else {
        if (re.test(urlAndValue.str)) {
            change();
        } else {
            add("&");
        }
    }
    return urlAndValue.str;
}
});

尝试以下:

$scope.str = "/root/get";
$scope.$apply();

您可以使用

$scope.$apply() 

将更改应用于函数中的范围。从本质上讲,它有助于迫使您的双向数据结合开始,以启动并抓住范围的新更改。如果正确实现数据绑定,则不必一定使用此命令,但是它确实可以用作肮脏的快速骇客。

相关内容

  • 没有找到相关文章

最新更新