5
votes

In my Ionic app there is a listView with cards on which users can click. After clicking they should see a page with more details. All content is in a pouchDB database (and also remotely in Firebase). The code to generate this list is below:

        <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-alt="{{ challenge.resources[0].caption }}" 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-alt="{{ challenge.resources[0].caption }}" 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>

Unfortunately, on an iPhone 5 (iOS 10.2) and Samsung Galaxy S4 Mini (Android 4.4) clicking on a card does not show the details of that card (see image below). On an iPhone 5s and Samsung Galaxy S4 (Android 5) this works correctly (see second image below). Empty screen - Details not shown

Working example

The function goToChallenge is defined as follows in the controller:

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

The NavigationService has the following code:

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;
};

Does anyone know how to solve this issue, please? I have been looking for a few days now and can't figure out why. Thanks!

EDIT

When I check with chrome://inspect in a virtual device (via Genymotion), I get the following error in the console

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

The onAfterEnter code block can be found below.

    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.clientHeight}px`;
        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);
        });
};

When I check in an iPhone 5 simulator (via XCode) I get the following similar error

Error: popovers.forEach is not a function. (In 'popovers.forEach', 'popovers.forEach' is undefined)

So it has to do with the popovers. Could it be that $window.document.querySelectorAll('.message-popover') does not return anything? The div with the message-popover class are initially hidden on the page and only shown when a certain condition is met (with ng-show).

1
Have you checked the developer console for errors on the mentioned devices?Phonolog
@bert did u tried with the crosswalk plugin for the android and test it in two device and let me know it went well or notThe Blue Shirt Developer
@Webruster, no have not tried that yet. But that would only solve the issue on Android and not on iPhone, I guess. The issue happens both on Android and iOS. So I guess it has to do with something else?Bert Carremans
@BertCarremans , check in android and let me know, will provide a way to work in iOSThe Blue Shirt Developer
It seems that the error is for using a non-array object as array.I. Ahmed

1 Answers

0
votes

It seems that your page is not completely rendered in those case you reach the foreach error. have you tryed to set a timeout or similar before execute the querySelectorAll on the page?