jjzjj

javascript - 在 DOM 中移动 Controller 时保留元素/范围状态

coder 2025-01-21 原文

在一个 Angular 应用程序中,我想将一个元素从 DOM 树的一部分移动到另一部分,而不必重新加载附加到移动元素的 Controller 。

我创建了一个简化的 plunker 来说明:http://plnkr.co/edit/sqBRM3ZQ5G9xpiNd1MXm?p=preview

在这个 plunker 中,唯一要保留的数据是切换器状态,但实际上它可能是非常大量的数据,可能需要花费大量精力来初始化。

我想要做的是能够将模板 1 从指令 1 移动到指令 2,但我想保留切换器的状态。在这种情况下,如果单击切换器使其变为绿色,然后单击“从列表 1 移动到 2”两次,它会将其移动到指令 2,但会将颜色重置为红色。

为了避免这种情况,我可以在不通知 Angular 情况下移动元素,但这显然会创建一个损坏的应用程序状态。

我考虑将 Controller 从旧范围移动到新范围,但我觉得这会导致关闭问题,因为旧 Controller 可能引用不再在 DOM 中的旧元素等。

有没有解决这个问题的好方法?

添加一些代码,因为 StackOverflow 需要它,但请引用 plunker:

angular.module('app').controller('bodyController', ['$element', function ($element) {

    this.contents1 = [{
        path: 'template1.html'
    }, {
        path: 'template2.html'
    }];

    this.contents2 = [{
        path: 'template3.html'
    }, {
        path: 'template4.html'
    }];

    this.move12 = function () {
        this.contents2.push(this.contents1.pop());
    };

    this.move21 = function () {
        this.contents1.push(this.contents2.pop());
    };

    this.naiveMove12 = function () {
        var $elem = $($element);
        $elem.find('container-list:eq(0) > div').last()
            .appendTo($elem.find('container-list').eq(1));
    };

    this.naiveMove21 = function () {
        var $elem = $($element);
        $elem.find('container-list:eq(1) > div').last()
            .appendTo($elem.find('container-list').eq(0));
    };

    this.logScope = function () {
        var $elem = $($element);
        [].forEach.call($elem.find('container-list'), function (elem, idx) {
            console.log(idx + ': ', angular.element(elem).isolateScope().containerListCtrl);
        });
    };
}]);

最佳答案

根据我的经验,将应用程序状态与 View / Controller 耦合并不是最佳实践,但这里有一种方法: revised plunkr .
template1.html 有一些小的变化.唯一的其他变化是 templateController.js :

angular.module('app').controller('templateController', statefulTemplateCtrl());

function statefulTemplateCtrl() {
  var state = {color: 'red'};
  return function(){
    this.state = state;

    // this.color = 'red';

    this.toggleColor = function () {
        state.color = (state.color === 'red') ? 'green' : 'red';
    };
  };
}

函数现在用作 templateController已配置为维护对 state 的引用目的。现在,如果您使用 bodyCtrl.move12() 移动模板,您将能够在不破坏应用程序状态的情况下保持累积的切换状态。这是因为 Controller 通过闭包引用了外部对象。因此,它可以通过 ng-include 在新的 DOM 节点上重新实例化和重新编译。无需重新启用 state .

可能是处理 的更好方法

使用服务和/或 $scope events API 在应用程序中的不同 DOM 节点之间共享状态。

假设您有模板,与您的 plunker 中引入的模板相同:
<div ng-class="{ red: (tc.color === 'red'), green: (tc.color === 'green') }" ng-click="tc.toggleColor()">Toggler</div> 

你想移动tc包含所有切换相关状态的对象到 DOM 中的另一个节点,您可以:
  • 发送事件 向下范围层次结构 $scope.$broadcast('nameOfEvent', tc)如果目标节点是源的后代$scope
  • 发送事件 向上范围层次结构 如果 $scope.$emit('nameOfEvent', tc)如果目标节点是源的祖先 $scope
  • 发送事件 到您的应用程序中的所有节点通过注入(inject) $rootScope$rootScope.$broadcast('nameOfEvent', tc)如果目标节点可以是任何一个。

  • 调用 $scope 事件 API 的任何这些方法将允许您传输数据,在本例中为 tc对象,从一个节点到另一个节点。与目标节点关联的目标 Controller 可以等待事件被分派(dispatch),监听器函数能够接收传输的数据:
    function bindDataToController(destinationCtrl){
      return function(event, tc){
        angular.extend(destinationCtrl, tc);
      };
    } 
    
    $scope.$on('nameOfEvent', bindDataToController(this));
    

    传输的数据对象,tc ,将在收到触发的 'nameOfEvent' 时绑定(bind)到与新目标节点关联的 Controller .现在源数据已与目标 Controller 对象合并,请确保为您的目标 Controller 提供相同的 controllerAs名称为您的源 Controller ,在本例中为 'tc' ,以便源模板在最终编译并附加到目标 DOM 节点后可以正确引用目标 Controller (该过程将在下面讨论)。

    正如您所提到的,删除和添加 DOM 节点有些微不足道,所以我没有在这里讨论它,但是如果您希望轻松访问源 View /模板以根据需要在应用程序的任何位置添加和删除,您可以使用 $templateCache .

    回到切换示例,如果您的切换 View /模板本身已经是使用 templateUrl 的指令的一部分文件路径为 'toggle.html' ,那么您的模板将已被放入并存储在 $templateCache在关键 'toggle.html' 下.

    在您的目标 Controller 中,注入(inject) $templateCache ,这将允许您检索模板:
     var template = $templateCache.get('toggle.html');
    

    将 $compile 注入(inject)您的目标 Controller 并使用目标 $scope 对模板进行 $compile (也注入(inject)目标 Controller ):
    var $template = $compile(template)($scope);
    

    然后将编译后的模板附加到 $element (也注入(inject)到目标 Controller 中)与您的目标 Controller 相关联:
    $element.append($template);
    

    如果您只想编译和附加 'toggle.html'收到传输的数据后将模板复制到 DOM,您可以将上述命令式编译代码放在 bindDataToController 的返回函数中,注册为 'nameOfEvent' 的事件监听器.就这样!... 一个 DOM 节点已被“移动”,具有先前在源位置建立的任何复杂状态。

    关于javascript - 在 DOM 中移动 Controller 时保留元素/范围状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32579737/

    有关javascript - 在 DOM 中移动 Controller 时保留元素/范围状态的更多相关文章

    1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

      我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

    2. ruby - 多次弹出/移动 ruby​​ 数组 - 2

      我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby​​数组,我们在StackOverflow上找到一

    3. ruby-on-rails - 渲染另一个 Controller 的 View - 2

      我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

    4. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

      刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

    5. ruby-on-rails - rails : How to make a form post to another controller action - 2

      我知道您通常应该在Rails中使用新建/创建和编辑/更新之间的链接,但我有一个情况需要其他东西。无论如何我可以实现同样的连接吗?我有一个模型表单,我希望它发布数据(类似于新View如何发布到创建操作)。这是我的表格prohibitedthisjobfrombeingsaved: 最佳答案 使用:url选项。=form_for@job,:url=>company_path,:html=>{:method=>:post/:put} 关于ruby-on-rails-rails:Howtomak

    6. ruby - 触发器 ruby​​ 中 3 点范围运算符和 2 点范围运算符的区别 - 2

      请帮助我理解范围运算符...和..之间的区别,作为Ruby中使用的“触发器”。这是PragmaticProgrammersguidetoRuby中的一个示例:a=(11..20).collect{|i|(i%4==0)..(i%3==0)?i:nil}返回:[nil,12,nil,nil,nil,16,17,18,nil,20]还有:a=(11..20).collect{|i|(i%4==0)...(i%3==0)?i:nil}返回:[nil,12,13,14,15,16,17,18,nil,20] 最佳答案 触发器(又名f/f)是

    7. ruby-on-rails - 跳过状态机方法的所有验证 - 2

      当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

    8. ruby-on-rails - 相关表上的范围为 "WHERE ... LIKE" - 2

      我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que

    9. ruby - 当使用::指定模块时,为什么 Ruby 不在更高范围内查找类? - 2

      我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or

    10. ruby-on-rails - 如何在 Rails Controller Action 上触发 Facebook 像素 - 2

      我有一个ruby​​onrails应用程序。我按照facebook的说明添加了一个像素。但是,要跟踪转化,Facebook要求您将页面置于达到预期结果时出现的转化中。即,如果我想显示客户已注册,我会将您注册后转到的页面作为成功对象进行跟踪。我的问题是,当客户注册时,在我的应用程序中没有登陆页面。该应用程序将用户带回主页。它在主页上显示了一条消息,所以我想看看是否有一种方法可以跟踪来自Controller操作而不是实际页面的转化。我需要计数的Action没有页面,它们是ControllerAction。是否有任何人都知道的关于如何执行此操作的gem、文档或最佳实践?这是进入布局文件的像素

    随机推荐