【问题标题】:Calling controller function from directive does not update view从指令调用控制器函数不会更新视图
【发布时间】:2015-06-12 11:07:17
【问题描述】:

我正在创建一个应用程序,其中 Ajax 请求从服务器获取包列表并显示它们。 之后,我创建了一个名为“packageDetails”的指令,该指令应用于单个包。

指令必须做两件事:

1- 单击元素时通过 AJAX 请求从服务器获取详细信息

2- 从页面的其他地方选取一些 HTML 并将其插入到被点击的包旁边。

我的问题:单击包时,AJAX 请求正在从服务器获取详细信息,并且正在操纵 DOM。我还可以看到范围变量$scope.packageDetails 在控制器中得到更新。但变化并没有反映在视图中。 但是,如果我再次单击一个包,这次视图会更新。

到目前为止我所尝试的:

在指令和控制器中都使用了 scope.$apply。这似乎是其他开发人员最常见的问题,但并没有解决我的问题。

尝试在元素中使用 ng-click,但没有成功。

Plunker

代码如下:

控制器

/*
an array that creates the rows and columns
$scope.packageList = [];
*/
$scope.getPackageDetails = function (packageId) {
    console.log('get details for ' + packageId);
    ajaxService.getPackageDetails(packageId).then(function (data) {
        if (parseInt(data.ResponseStatus, 10) === 0) {
            $scope.packageDetails = data.Packages;
            // i have tried $scope.$apply() here; doesn't work
        }
    });

查看

<div class="row" ng-repeat="columnPackages in packageList">
    <div class="col-md-3 onePackage" ng-repeat="package in columnPackages" package-details package-id="{{package.Id}}" click="getPackageDetails"  has-response="response" >
        <figure>
            <a class="package_view">
                <strong>{{package.Name}}</strong>
            </a>
        </figure>
    </div>
</div>

指令

epApp.directive('packageDetails', function () {
    return {
        scope:
        {
            hasResponse: '=hasResponse',
            click: '=click'
        },
        link: function (scope, elem, attrs) {            
            if (scope.$parent.$last) {
                $(elem).parent('div.row').find('div.onePackage').on('click', function () {
                    /* some dom manipulation */
                    var packages_content = jQuery('.packages_widget_append').html();
                    jQuery(this).closest(".row").after(packages_content);

                    /* called parent controller function to get the details*/
                    console.log('clicked ' + parseFloat(attrs.packageId));
                    scope.click(parseFloat(attrs.packageId));
                    // i have tried $scope.$apply() here as well; doesn't work

                });
            }
        }
    }

});

请帮忙。

谢谢。

【问题讨论】:

  • 调用$apply时是否报错?您是否尝试过使用 $timeout(没有延迟)?
  • 如果我在指令中调用 $apply,则没有错误,但如果我在收到响应后立即从控制器调用它,则会收到错误 Error: [$rootScope:inprog] http://errors.angularjs.org/1.2.28/$rootScope/inprog?p0=%24digest z/&lt;@http://localhost/EPV2/js/vendor/angular.min.js:6:450
  • 正如 c0bra 提到的,尝试将它包装在 $timeout 周围,不要延迟。这不会给您带来正在进行的摘要错误。
  • @AbhishekJain 也立即尝试超时。还是不行。
  • 你能为此创建一个 plunker 吗?

标签: jquery angularjs angularjs-directive angularjs-scope


【解决方案1】:

1.: 你忘记了函数的 put 参数吗? :-)

click="getPackageDetails(package.Id)"

而不是

click="getPackageDetails"

【讨论】:

    【解决方案2】:

    我想你想要一些东西,但你不知道如何用 Angular 来做。 你使用 jQuery,但没有它你也可以做到 :)

    通过您的示例,我看到了两种可能的解决方案:

    1) 您在控制器中完成所有操作

    您声明了一个尝试执行一些 DOM 操作的指令,如果您决定不这样实现它,您可以结合 ng-show/ng-hide 等显示/隐藏包详细信息... 点击可以通过 ng-click 处理。

    像这样,没有更多的 DOM 操作,不需要手动做范围。$apply。

    2) 你想用指令来做

    您的 package-details 指令应该是 Element 指令。在其中您也可以定义您的模板并正确使用绑定。 您将传递您的包数组并对其进行循环。

    对于点击句柄,有两种选择,将您的控制器功能传递到您的指令中或在指令中使用您的 Ajaxservice。我认为第二个比第一个更容易,如果你的指令不是真的通用,你应该考虑采用这个解决方案。

    Plunker 1 : http://goo.gl/rUzKWn

    Plunker for 2(服务):http://goo.gl/yixa7U

    我不确定是否能正确回答您的问题,但也许这可以为您提供一些想法来做您想做的事!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-06
      • 1970-01-01
      • 1970-01-01
      • 2015-10-21
      相关资源
      最近更新 更多