未捕获的类型错误:无法使用弹出框读取 null 的属性'attr'



我正在使用onsen ui 1.3.13,我得到了一个我不理解的错误:未捕获的类型错误:无法使用popover@loader.js:1450 读取null的属性"attr"

我基本上有一个按钮,当我点击它时,我会看到一个弹出窗口和另外两个按钮。按钮2在数组上执行简单的弹出操作。情况更糟了,但马上给我这个错误。

这是我的代码:

index.html

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <script src="components/loader.js"></script>
    <script src="js/controler.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js"></script>
    <script src="js/angular-moment.js"></script>
    <script src="js/readable-range.js"></script>
    <link rel="stylesheet" href="components/loader.css">
    <link rel="stylesheet" href="css/style.css">
    <link rel="stylesheet" href="css/sliding_menu.css">
</head>
<body>
    <ons-sliding-menu main-page="initial.html" menu-page="menu.html" max-slide-distance="260px" type="overlay" var="menu" side="left" close-on-tap>
    </ons-sliding-menu>
    <ons-template id="menu.html">
        <ons-page modifier="menu-page">
            <ons-toolbar modifier="transparent">
                <div class="right">
                    <ons-toolbar-button class="menu-closeMenu" ng-click="menu.closeMenu()">
                        </ons-icon>Close
                    </ons-toolbar-button>
                </div>
            </ons-toolbar>
            <ons-list class="menu-list" ng-controller="PopoverController">
                <ons-list-item class="menu-item" ng-click="menu.setMainPage('initial.html', {closeMenu: true})">
                    <ons-icon icon="fa-gbp"></ons-icon>
                    Initial page
                </ons-list-item>
                <ons-list-item class="menu-item" ng-click="reset();menu.closeMenu()">
                    <ons-icon icon="fa-gbp"></ons-icon>
                    reset
                </ons-list-item>
            </ons-list>
        </ons-page>
    </ons-template>
    <ons-template id="popover.html">
        <ons-popover direction="down" cancelable>
                <ons-list>
                    <ons-list-item modifier="tappable" ng-click="alert(true, 'Sorry not available in this version')">
                        <ons-icon icon="fa-cloud"></ons-icon>
                        Save property
                    </ons-list-item>
                    <ons-list-item modifier="tappable" ng-click="reset(); destroy($event)" >
                        <ons-icon icon="fa-home"></ons-icon>
                        <label>Reset</label>
                    </ons-list-item>
                </ons-list>
        </ons-popover>
    </ons-template>
</body>
</html>

controler.js:

var app = ons.bootstrap('propertyDeal', ['onsen','angularMoment']);
    app.factory('Property', function () {
        /**
        * Constructor, with class name
        */
        function Property(newProperty) {
            this.id = newProperty.id;
            this.purchasePrice = newProperty.pprice;
            this.legaFee = newProperty.legal;
          }
        return {
            createNew: function(newProperty) {
                return new Property(newProperty);
            }
        };
    });

    app.factory('portfolio', function(Property){
        var portfolio = {};
        portfolio.list = [];
        portfolio.add = function(newProperty){
            var prop = Property.createNew(newProperty);
            portfolio.list.push(prop);
        };
        portfolio.remove = function(){
            var removed = portfolio.list.pop();
        };
        return portfolio;
    });
    app.controller('PopoverController', function($scope, portfolio) {
        $scope.popurl = function(url, e) {
            $scope.param = url; 
            ons.createPopover( $scope.param,{parentScope: $scope}).then(function(popover) {
                $scope.popover = popover;
                $scope.show(e);
            });
            $scope.show = function(e) {
                $scope.popover.show(e);
            };
            $scope.destroy = function(e) {
                $scope.popover.destroy(e);
            };
        };
        $scope.alert = function(material, message) {
            ons.notification.alert({
                message: message,
                modifier: material ? 'material' : undefined
            });
        };
        $scope.reset = function() {
            if (portfolio.list.length >= 1){
                portfolio.remove();
            }
        };
    });
    app.controller('ListCtrl', function(portfolio) {
        this.portfolio = portfolio.list;
    });
    app.controller('PostCtrl', function(portfolio){
        this.addProperty = function(newProperty){
            if (angular.isDefined(newProperty)) {
                newProperty.id = portfolio.list.length;
                portfolio.add(newProperty);
            }
        };
    });

initial.html

<ons-navigator>
<ons-page>
    <div class="container">
        <ons-toolbar>
            <div class="left">
                <ons-toolbar-button ng-click="menu.toggleMenu()">
                    <ons-icon icon="ion-navicon" size="28px" fixed-width="false"></ons-icon>
                </ons-toolbar-button>
                <ons-icon class="icon" icon="ion-android-share"></ons-icon>&nbsp;this is a test
            </div>
            <div class="right" ng-controller="PopoverController">
                <ons-toolbar-button id="android-share" ng-click="popurl('popover_share.html', $event)">
                    <ons-icon icon="ion-android-share" fixed-width="false"></ons-icon>
                </ons-toolbar-button>
                <ons-toolbar-button id="android-more" ng-click="popurl('popover.html', $event)">
                    <ons-icon icon="ion-android-more-vertical" fixed-width="false"></ons-icon>
                </ons-toolbar-button>
            </div>
        </ons-toolbar>
    </div>
    <div style="text-align: center">
        <h2>Page 1</h2>
        <ul class="list">
                <input type="hidden" ng-model="newProperty.id" placeholder="id">
            <li class="list__item">
                <span class="currency">£<input type="number" class="text-input text-input--transparent" style="width:100%; margin-top:4px;" ng-model="newProperty.pprice" placeholder="Purchase price" required></span>
            </li>
            <li class="list__item">
                <span class="currency">£<input type="number" class="text-input text-input--transparent" style="width:100%; margin-top:4px;" ng-model="newProperty.legal" placeholder="Legal fees"></span>
            </li>
        </ul>
    </div>
    <br />
    <div ng-controller="PostCtrl as post">
        <button class="button" ng-click="post.addProperty(newProperty);menu.setMainPage('initial2.html')">Next <ons-icon icon="ion-arrow-right-b"></ons-icon></button>
        <p>{{newProperty}}</p>
    </div>
    <div ng-controller="ListCtrl as list">
        <p ng-repeat="prop in list.portfolio track by $index">
            New Property: {{prop.id}} - {{prop.purchasePrice}}: {{prop.legaFee}} </p>
    </div>
</ons-page>
</ons-navigator>

在将reset()添加到滑动菜单后,我也可以说它与滑动菜单配合得很好,所以我认为这肯定是popover的问题,但我不知道是什么。

感谢您的帮助

在该代码中,您正在一次又一次地创建和销毁popover。问题不在reset()函数中,而在destroy()函数中。你在展示popover时试图破坏它,这是一个时间问题。在内部,当它已经被摧毁时,它试图检查自己的位置。即使现在没有消失的动画,因为你只是销毁它而不是隐藏它。

解决方案是在演出后创建弹出窗口,并在需要时隐藏它们。希望它能有所帮助!

更新

你现在使用它的方式实际上存在内存泄漏。您每次单击工具栏按钮时都会创建popover,并在reset()函数中销毁它。问题是,如果你显示弹出窗口,然后点击它的外部,它将被隐藏而不会被破坏,所以下次你打开弹出窗口时,它会创建另一个。您可以检查您的DOM,并看到每增加一个popover。

使用popover的正确方法是只创建一次,然后在需要时显示和隐藏它。只有当你不再需要它的时候,你才需要摧毁它。有一种方法可以自动完成:

$scope.$on('$destroy', $scope.myPopover.destroy);

当您更改到另一个作用域时,这将破坏当前作用域中的popover。

最新更新