使用 listView 和 PouchDb 的 Ionic (v1) 应用程序出现问题

Posted

技术标签:

【中文标题】使用 listView 和 PouchDb 的 Ionic (v1) 应用程序出现问题【英文标题】:Issue with Ionic (v1) app using listView and PouchDb 【发布时间】:2018-06-15 17:41:16 【问题描述】:

在我的 Ionic 应用程序中,有一个带有卡片的 listView,用户可以点击它。单击后,他们应该会看到一个包含更多详细信息的页面。所有内容都在 pouchDB 数据库中(也远程在 Firebase 中)。生成此列表的代码如下:

        <div class="card" ng-repeat="challenge in vm.challenges track by $index" ng-class="'bounceInLeft': $index % 2 !== 0, 'bounceInRight': $index % 2 === 0" ng-click="vm.goToChallenge(challenge)">
        <div class="item item-text-wrap">
            <div class="resource">
                <img ng-src=" challenge.resources[0].image " ng-attr- ng-srcset=" challenge.resources[0].srcset " ng-if="challenge.resources && challenge.resources[0].type === 'img'">
                <img ng-src=" challenge.resources[0].url | getYouTubeImage " ng-attr- ng-if="challenge.resources && challenge.resources[0].type === 'video'">
                <i class="ion-play" ng-if="challenge.resources && challenge.resources[0].type === 'video'"></i>
            </div>
            <p class="category"> challenge.categoryName </p>
            <p class="name"> challenge.name </p>
        </div>
        <div class="item footer item-divider">
            <div class="row">
                <div class="col col-50">
                    <i class="ion-calendar"></i>  challenge.seasonsObjects.join(', ') 
                </div>
                <div class="col col-50">
                    <div>
                        <i class="ion-bookmark" ng-repeat="bookmark in (challenge.ranking + 1) | range track by $index"></i>
                    </div>
                     challenge.rankingName 
                </div>
            </div>
        </div>
    </div>

很遗憾,在 iPhone 5 (ios 10.2) 和三星 Galaxy S4 Mini (android 4.4) 上,点击卡片不会显示该卡片的详细信息(见下图)。在 iPhone 5s 和三星 Galaxy S4 (Android 5) 上,这可以正常工作(见下面的第二张图片)。

函数goToChallenge在控制器中定义如下:

vm.goToChallenge = (challenge) => 
    NavigationService.go('home.challenge', 
        challenge: challenge._id
    );
;

NavigationService 的代码如下:

angular.module('starter').factory('NavigationService', ['$window', '$q', 'ionic', '$state', '$ionicHistory', '$ionicLoading', '$ionicPopup', '$cordovaNativeAudio', '$cordovaSocialSharing', '$cordovaNetwork', '$ionicSideMenuDelegate', '$ionicNavBarDelegate', '$ionicTabsDelegate', NavigationService]);

function NavigationService($window, $q, ionic, $state, $ionicHistory, $ionicLoading, $ionicPopup, $cordovaNativeAudio, $cordovaSocialSharing, $cordovaNetwork, $ionicSideMenuDelegate, $ionicNavBarDelegate, $ionicTabsDelegate) 
let factory = ;
// Set root of history stack to the registration page with historyRoot: true
// Disable animation from slider to registration page to avoid weird transition
// in wich the header bar pops down. This is because we do not have a header bar in the slider
factory.setRootAndGo = (state, params = ) => 
    $ionicHistory.nextViewOptions(
        historyRoot: true,
        disableAnimate: true
    );
    factory.go(state, params);
;
factory.go = (state, params = ) => 
    $state.go(state, params, 
        location: 'replace',
        reload: true
    );
;
factory.replace = (state, params = ) => 
    $ionicHistory.currentView($ionicHistory.backView());
    factory.go(state, params);
;
factory.toggleMenu = () => $ionicSideMenuDelegate.toggleRight();
factory.showTabs = () => 
    $ionicTabsDelegate.showBar(true);
;
factory.hideTabs = () => 
    $ionicTabsDelegate.showBar(false);
;
factory.setTitle = (title) => $ionicNavBarDelegate.title(title);
factory.getParams = () => $state.params;
factory.getNavHistory = () => $ionicHistory.viewHistory();
factory.showLoading = (options) => $ionicLoading.show(options);
factory.hideLoading = () => $ionicLoading.hide();
factory.isWebView = () => ionic.Platform.isWebView();
factory.isOffline = () => factory.isWebView() && $cordovaNetwork.isOffline();
factory.goToWebPage = (url) => $window.open(url, '_system');
factory.shareFacebook = (text, img, url) => 
    let defer = $q.defer();
    $cordovaSocialSharing.shareViaFacebook(text, img, url)
        .then(defer.resolve, defer.reject);
    return defer.promise;
;
factory.shareTwitter = (text, img, url) => 
    let defer = $q.defer();
    $cordovaSocialSharing.shareViaTwitter(text, img, url)
        .then(defer.resolve, defer.reject);
    return defer.promise;
;
factory.playSound = (name) => $cordovaNativeAudio.play(name);
factory.alert = (title, text) => $ionicPopup.alert(
    title: title,
    template: text
);
return factory;
;

请问有人知道如何解决这个问题吗?我已经找了几天了,不知道为什么。谢谢!

编辑

当我在虚拟设备中检查 chrome://inspect(通过 Genymotion)时,我在控制台中收到以下错误

TypeError: Object # has no method 'forEach' 在 ChallengeCtrl.vm.onAfterEnter (file:///android_asset/www/build/app.js:226:12) 在 m.$emit (file:///android_asset/www/lib/ionic/js/ionic.bundle.min.js:178:407) 在 Object.q.emit (file:///android_asset/www/lib/ionic/js/ionic.bundle.min.js:470:20592) 在 m (file:///android_asset/www/lib/ionic/js/ionic.bundle.min.js:470:19062) 在 htmlElement.g (file:///android_asset/www/lib/ionic/js/ionic.bundle.min.js:470:18921) 在 Pf (file:///android_asset/www/lib/ionic/js/ionic.bundle.min.js:70:477) 在 HTMLElement.Of.d (file:///android_asset/www/lib/ionic/js/ionic.bundle.min.js:70:424) ionic.bundle.min.js:150

onAfterEnter 代码块可以在下面找到。

    vm.onAfterEnter = () => 
    //let ionViewDOM = $window.document.querySelectorAll('.challenge.pane .scroll-content')[0];
    let ionViewDOM = $window.innerHeight - 43;  // innerHeight minus the heigh of the title bar
    let popovers = $window.document.querySelectorAll('.message-popover');
    popovers.forEach((popover) => 
        //popover.style.height = `$ionViewDOM.clientHeightpx`;
        popover.style.height = ionViewDOM + `px`;
        if (ionViewDOM.clientHeight < 450) 
            popover.classList.add('small-screen');
         else if (ionViewDOM.clientHeight < 550) 
            popover.classList.add('medium-screen');
         else 
            popover.classList.remove('small-screen');
            popover.classList.remove('medium-screen');
        
    );

    let params = NavigationService.getParams();
    ChallengeService.get(params.challenge)
        .then((result) => 
            vm.challenge = result;

            switch (vm.challenge.status) 
                case 'accepted':
                    vm.challengeAccepted = true;
                    break;
                case 'completed':
                    vm.challengeCompleted = true;
                    break;
            
            NavigationService.setTitle(vm.challenge.gardenType.name);
            vm.challengeLoaded = true;

            ChallengeService.listRandomAvailableForUser(params.challenge, vm.challenge.gardenType.challenges)
                .then((result) => vm.randomChallenges = result);
        );
;

当我签入 iPhone 5 模拟器(通过 XCode)时,我收到以下类似错误

错误:popovers.forEach 不是函数。 (在“popovers.forEach”中, 'popovers.forEach' 未定义)

所以它与弹出框有关。难道$window.document.querySelectorAll('.message-popover') 没有返回任何东西? message-popover 类的 div 最初隐藏在页面上,仅在满足特定条件时显示(使用 ng-show)。

【问题讨论】:

您是否检查了开发者控制台中提到的设备上的错误? @bert 您是否尝试过使用适用于 android 的人行横道插件并在两台设备上对其进行测试,然后让我知道它是否顺利 @Webruster,还没有尝试过。但这只会解决Android上的问题,而不是iPhone上的问题,我猜。该问题发生在 Android 和 iOS 上。所以我猜这与其他事情有关? @BertCarremans ,签入 android 并告诉我,将提供一种在 iOS 中工作的方法 似乎错误是使用非数组对象作为数组。 【参考方案1】:

在您遇到 foreach 错误的情况下,您的页面似乎没有完全呈现。在页面上执行 querySelectorAll 之前,您是否尝试过设置超时或类似设置?

【讨论】:

以上是关于使用 listView 和 PouchDb 的 Ionic (v1) 应用程序出现问题的主要内容,如果未能解决你的问题,请参考以下文章

PouchDB 和 CouchBase Lite + LiteGap 的区别

跨平台存储与同步:IonicCouchbase和PouchDB结合使用范例

ionic 上的 Pouchdb 和 Cordova-sqlcipher-adapter:有可能吗?

PouchDB:JavaScript同步数据库

同一设备上的每个用户一个pouchDB与单个CouchDB同步

使用 PouchDB 的 Ionic 应用程序性能问题