如何让Angular JS使用哈希URL来表示一个动作?

时间:2015-06-16 18:50:06

标签: angularjs

TL; DR;

我编写了一个程序,该程序使用DOM操作和jQuery来响应用户在hash-URL中输入以逗号分隔的值列表,并希望在Angular中执行此操作。

长版

在我的业余时间里,我一直在写一个程序,它可以绘制分形图像,例如着名的Mandelbrot分形图。这是网址:http://danielsadventure.info/html5fractal/docs/intro.html。我这样做是为了使用canvas元素和web worker等功能来展示我的HTML5肌肉。该计划效果很好。这是" Negabrot"的渲染图像。我的计划中的分形:

enter image description here

最近,我一直在教自己Angular,我决定使用Angular而不是jQuery重写Javascript。再一次,我这样做是为了练习。

Angular确实是一个非常合适的工具,因为用户可以使用许多表单来描述要绘制的分形图像。我能够使用Angular将模型绑定到表单并删除我之前使用的DOM操作代码。好极了! Angular太棒了!

我的程序的另一个特性是,我不清楚如何将其转换为与Angular一起使用。我的程序是单页应用程序。它只做一件事:绘制分形图像。但是,我使用哈希URL来跟踪正在绘制的分形以及用于绘制分形的配置。例如,您可以按照以下网址查看Multibrot-5分形的放大部分:

http://danielsadventure.info/html5fractal/index.html#103,0.41000000000000014,1.0299999999999998,0.41999999999999993,1.04,2,1261,true,z%20 ^%205%20%2B%20C,-2,2,-2,2

如您所见,URL由逗号分隔值列表组成,这些值描述了程序配置的不同方面。如果你用它绘制一些美丽的东西,你可以简单地向其他人发送URL,他们可以绘制相同的东西;像馅饼一样容易!

为了实现这一点,我通过更新表单上的配置,再次使用老式的DOM操作,监听指示hash-URL已更改并响应它的事件。

我之前在StackOverflow上询问过如何响应hash-URL,我被引导到ngRoute。 ngRoute看起来非常有用,但看起来它主要与模板和控制器相关联。

在我的程序中,我不需要加载任何其他模板。我只需要通过更新配置和绘制新的分形来响应新的哈希URL。我还想在用户手动更新配置并绘制新的分形时更新hash-URL。

简而言之,我想要发生的是:

当用户输入新的hash-URL时,程序应该通过更新绑定到输入的模型来响应,以便表单值发生变化。

当用户手动更改输入并单击按钮再次绘制时,应使用新配置更新散列URL。

2 个答案:

答案 0 :(得分:2)

使用angular ui-router你可以这样做:

angular.module('demoApp', ['ui.router'])
    .config(function($stateProvider, $urlRouterProvider) {
        //
        // For any unmatched url, redirect to /fractal
        $urlRouterProvider.otherwise("/fractal?minr=-0.29&maxr=-0.27&mini=-0.64");
        //
        // Now set up the states
        $stateProvider
           .state('fractal', {
              url: '/fractal?minr&maxr&mini',
              templateUrl: 'app/partials/fract.html',
              controllerAs: 'fract',
              controller: function($stateParams) {
                  console.log($stateParams);
                  var fract = new Fractal($stateParams);
                  this.getSettings = fract.getSettings;
              }
       });
});

url属性中,您可以指定参数。我已经选了你的一些参数。

$stateParams服务将注入在网址中传递的所有参数。

以下只是为了展示我是如何实现Fractal类的:

function Fractal(settings) {
    var that = this;
    this.settings = settings;

    this.getSettings = function() {
        return that.settings;
    }
}

部分fract.html看起来像这样(它只输出设置):

<h1>Drawing fractal in this state</h1>
<hr/>
{{fract.getSettings()|json}}

在你的应用中,你可能会为你的分形类创建一个指令,因为你正在做DOM的东西。我只是在状态控制器中添加所有内容以保持演示简单。 您可以将指令添加到fractal.html部分。

请查看下面的演示或jsfiddle。请注意,您没有在jsfiddle中看到url参数。

在您的应用中,它们将出现在以下屏幕截图中: enter image description here

&#13;
&#13;
angular.module('demoApp', ['ui.router'])
	.config(function($stateProvider, $urlRouterProvider) {
  //
  // For any unmatched url, redirect to /state1
  $urlRouterProvider.otherwise("/fractal?minr=-0.29&maxr=-0.27&mini=-0.64");
  //
  // Now set up the states
  $stateProvider
    .state('fractal', {
      url: '/fractal?minr&maxr&mini',
      templateUrl: 'app/partials/fract.html',
      controllerAs: 'fract',
      controller: function($stateParams) {
      	console.log($stateParams);
      	var fract = new Fractal($stateParams);
        this.getSettings = fract.getSettings;
      }
    });
});

// here comes your fractal class
function Fractal(settings) {
  var that = this;
	this.settings = settings;

  this.getSettings = function() {
    return that.settings;
  }
}
&#13;
<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-ui-router/0.2.15/angular-ui-router.js"></script>

<div ng-app="demoApp">
    <script type="text/ng-template" id="app/partials/fract.html">
        <h1>Drawing fractal in this state</h1>
        <hr/>
        {{fract.getSettings()|json}}
    </script>

    <div ui-view></div>
    <!-- We'll also add some navigation: -->
    <a ui-sref="fractal({minr:-0.3, maxr:-0.2, mini: -0.64})">Draw fractal</a>
    
</div>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

好吧我不太确定你已有的JS代码,所以我要展示一些你可能会觉得有帮助的片段!

这是一个关于URL的监视 - 所以每次哈希更改时都会调用此函数:

$scope.$on('$locationChangeSuccess', function(event, newState, oldState) {
  var values = $location.hash().split(','); // => [103,true,...]
  var desc = ['point1', 'boolean']; // I don't know wich values you have..

  $scope.values = {}; // values model
  angular.forEach(values, function(value, index) {
    $scope.values[desc[index]] = value; // {'point1': 103} => nested attribute
  }); 
});

然后你可以将它绑定到一个表单:

// HTML
<form ng-submit="updateHash()">
  <input ng-model="values.point1" />
</form>

// JS
$scope.updateHash = function() {
  var updatedValues = [];
  angular.forEach($scope.values, function(value) {
    updatedValues.push(value);
  }); 
  $location.hash(updatedValues); // update URL
};