范围变量值的变化没有反映在我的字符串中

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了范围变量值的变化没有反映在我的字符串中相关的知识,希望对你有一定的参考价值。

我有以下字符串:

"/root/get";

现在我在上面的字符串中生成一个带有1个范围变量的查询字符串,但问题是当该变量的值发生变化时,新值不会自动更新到我的URL中。

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

我不明白为什么会这样。

单击检查按钮而不调用generateQueryParameters方法时的预期输出:

/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绑定一样作品?

答案

让我们从代码中的问题开始。您通过函数生成请求字符串,该函数实际上仅在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并将它们注入需要使用它们的位置。硬编码字符串不是一个好习惯。

另一答案

您可以使用新控制器作为语法轻松定义属性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>
另一答案

您需要为no添加观察器,它会调用您称为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>
另一答案

你需要在check方法中再次调用generateQueryParame

以上是关于范围变量值的变化没有反映在我的字符串中的主要内容,如果未能解决你的问题,请参考以下文章

从活动中更改片段的变量值

如何通过单击适配器类中代码的项目中的删除按钮来删除列表视图中的项目后重新加载片段?

中断变量值的变化

如何在我的 aspx 页面上显示变量值背后的代码

在 C 中给出 unsigned long long 变量值的警告

通过子程序将一组变量值传递给没有公共块的函数都有哪些方法?