diff --git a/src/addon/mod/data/components/action/action.ts b/src/addon/mod/data/components/action/action.ts
index dab8a35d0..32be60ec3 100644
--- a/src/addon/mod/data/components/action/action.ts
+++ b/src/addon/mod/data/components/action/action.ts
@@ -30,6 +30,7 @@ export class AddonModDataActionComponent implements OnInit {
     @Input() action: string; // The field to render.
     @Input() entry?: any; // The value of the field.
     @Input() database: any; // Database object.
+    @Input() offset?: number; // Offset of the entry.
 
     siteId: string;
     rootUrl: string;
@@ -67,6 +68,9 @@ export class AddonModDataActionComponent implements OnInit {
         switch (this.action) {
             case 'more':
                 this.url = this.rootUrl + '/mod/data/view.php?d= ' + this.entry.dataid + '&rid=' + this.entry.id;
+                if (typeof this.offset == 'number') {
+                    this.url += '&mode=single&page=' + this.offset;
+                }
                 break;
             case 'edit':
                 this.url = this.rootUrl + '/mod/data/edit.php?d= ' + this.entry.dataid + '&rid=' + this.entry.id;
diff --git a/src/addon/mod/data/components/index/index.ts b/src/addon/mod/data/components/index/index.ts
index 9e32c7afb..9da9180fe 100644
--- a/src/addon/mod/data/components/index/index.ts
+++ b/src/addon/mod/data/components/index/index.ts
@@ -47,7 +47,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
     timeAvailableToReadable: string | boolean;
     isEmpty = false;
     groupInfo: CoreGroupInfo;
-    entries = {};
+    entries = [];
     firstEntry = false;
     canAdd = false;
     canSearch = false;
@@ -317,6 +317,8 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
                 });
 
                 return Promise.all(promises).then((entries) => {
+                    this.entries = entries;
+
                     let entriesHTML = this.data.listtemplateheader || '';
 
                     // Get first entry from the whole list.
@@ -326,12 +328,15 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
 
                     const template = this.data.listtemplate || this.dataHelper.getDefaultTemplate('list', this.fieldsArray);
 
-                    entries.forEach((entry) => {
-                        this.entries[entry.id] = entry;
+                    const entriesById = {};
+                    entries.forEach((entry, index) => {
+                        entriesById[entry.id] = entry;
 
                         const actions = this.dataHelper.getActions(this.data, this.access, entry);
+                        const offset = this.search.page * AddonModDataProvider.PER_PAGE + index;
 
-                        entriesHTML += this.dataHelper.displayShowFields(template, this.fieldsArray, entry, 'list', actions);
+                        entriesHTML += this.dataHelper.displayShowFields(template, this.fieldsArray, entry, offset, 'list',
+                                actions);
                     });
                     entriesHTML += this.data.listtemplatefooter || '';
 
@@ -340,7 +345,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
                     // Pass the input data to the component.
                     this.jsData = {
                         fields: this.fields,
-                        entries: this.entries,
+                        entries: entriesById,
                         data: this.data,
                         gotoEntry: this.gotoEntry.bind(this)
                     };
@@ -440,9 +445,16 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
             module: this.module,
             courseId: this.courseId,
             entryId: entryId,
-            group: this.selectedGroup
+            group: this.selectedGroup,
+            offset: null
         };
 
+        // Try to find page number and offset of the entry.
+        const pageXOffset = this.entries.findIndex((entry) => entry.id == entryId);
+        if (pageXOffset >= 0) {
+            params.offset = this.search.page * AddonModDataProvider.PER_PAGE + pageXOffset;
+        }
+
         this.navCtrl.push('AddonModDataEntryPage', params);
     }
 
diff --git a/src/addon/mod/data/pages/entry/entry.html b/src/addon/mod/data/pages/entry/entry.html
index c1d727795..a49acdf57 100644
--- a/src/addon/mod/data/pages/entry/entry.html
+++ b/src/addon/mod/data/pages/entry/entry.html
@@ -34,16 +34,16 @@
             <core-comments contextLevel="module" [instanceId]="data.coursemodule" component="mod_data" [itemId]="entry.id" area="database_entry"></core-comments>
         </ion-item>
 
-        <ion-grid *ngIf="previousId || nextId">
+        <ion-grid *ngIf="previousOffset != null || nextOffset != null">
             <ion-row align-items-center>
-                <ion-col *ngIf="previousId">
-                    <button ion-button block outline icon-start (click)="gotoEntry(previousId)">
+                <ion-col *ngIf="previousOffset != null">
+                    <button ion-button block outline icon-start (click)="gotoEntry(previousOffset)">
                         <ion-icon name="arrow-back" md="ios-arrow-back"></ion-icon>
                         {{ 'core.previous' | translate }}
                     </button>
                 </ion-col>
-                <ion-col *ngIf="nextId">
-                    <button ion-button block icon-end (click)="gotoEntry(nextId)">
+                <ion-col *ngIf="nextOffset != null">
+                    <button ion-button block icon-end (click)="gotoEntry(nextOffset)">
                         {{ 'core.next' | translate }}
                         <ion-icon name="arrow-forward" md="ios-arrow-forward"></ion-icon>
                     </button>
diff --git a/src/addon/mod/data/pages/entry/entry.ts b/src/addon/mod/data/pages/entry/entry.ts
index 8ea967f72..16a35f39e 100644
--- a/src/addon/mod/data/pages/entry/entry.ts
+++ b/src/addon/mod/data/pages/entry/entry.ts
@@ -41,7 +41,7 @@ export class AddonModDataEntryPage implements OnDestroy {
     protected module: any;
     protected entryId: number;
     protected courseId: number;
-    protected page: number;
+    protected offset: number;
     protected syncObserver: any; // It will observe the sync auto event.
     protected entryChangedObserver: any; // It will observe the changed entry event.
     protected fields = {};
@@ -55,8 +55,8 @@ export class AddonModDataEntryPage implements OnDestroy {
     offlineActions = [];
     hasOffline = false;
     cssTemplate = '';
-    previousId: number;
-    nextId: number;
+    previousOffset: number;
+    nextOffset: number;
     access: any;
     data: any;
     groupInfo: any;
@@ -77,7 +77,7 @@ export class AddonModDataEntryPage implements OnDestroy {
         this.entryId = params.get('entryId') || null;
         this.courseId = params.get('courseId');
         this.selectedGroup = params.get('group') || 0;
-        this.page = params.get('page') || null;
+        this.offset = params.get('offset');
 
         this.siteId = sitesProvider.getCurrentSiteId();
 
@@ -133,7 +133,7 @@ export class AddonModDataEntryPage implements OnDestroy {
             this.data = data;
             this.cssClass = 'addon-data-entries-' + data.id;
 
-            return this.setEntryIdFromPage(data.id, this.page, this.selectedGroup).then(() => {
+            return this.setEntryIdFromOffset(data.id, this.offset, this.selectedGroup).then(() => {
                 return this.dataProvider.getDatabaseAccessInformation(data.id);
             });
         }).then((accessData) => {
@@ -177,7 +177,7 @@ export class AddonModDataEntryPage implements OnDestroy {
             const actions = this.dataHelper.getActions(this.data, this.access, this.entry);
 
             const templte = this.data.singletemplate || this.dataHelper.getDefaultTemplate('single', fieldsArray);
-            this.entryRendered = this.dataHelper.displayShowFields(templte, fieldsArray, this.entry, 'show', actions);
+            this.entryRendered = this.dataHelper.displayShowFields(templte, fieldsArray, this.entry, this.offset, 'show', actions);
             this.showComments = actions.comments;
 
             const entries = {};
@@ -189,11 +189,6 @@ export class AddonModDataEntryPage implements OnDestroy {
                 entries: entries,
                 data: this.data
             };
-
-            return this.dataHelper.getPageInfoByEntry(this.data.id, this.entryId, this.selectedGroup).then((result) => {
-                this.previousId = result.previousId;
-                this.nextId = result.nextId;
-            });
         }).catch((message) => {
             if (!refresh) {
                 // Some call failed, retry without using cache since it might be a new activity.
@@ -210,13 +205,13 @@ export class AddonModDataEntryPage implements OnDestroy {
     /**
      * Go to selected entry without changing state.
      *
-     * @param  {number}       entry Entry Id where to go.
-     * @return {Promise<any>}       Resolved when done.
+     * @param  {number} offset Entry offset.
+     * @return {Promise<any>} Resolved when done.
      */
-    gotoEntry(entry: number): Promise<any> {
-        this.entryId = entry;
+    gotoEntry(offset: number): Promise<any> {
+        this.offset = offset;
+        this.entryId = null;
         this.entry = null;
-        this.page = null;
         this.entryLoaded = false;
 
         return this.fetchEntryData();
@@ -264,30 +259,56 @@ export class AddonModDataEntryPage implements OnDestroy {
      */
     setGroup(groupId: number): Promise<any> {
         this.selectedGroup = groupId;
+        this.offset = 0;
+        this.entry = null;
+        this.entryId = null;
         this.entryLoaded = false;
 
-        return this.setEntryIdFromPage(this.data.id, 0, this.selectedGroup).then(() => {
-            return this.fetchEntryData();
-        });
+        return this.fetchEntryData();
     }
 
     /**
-     * Convenience function to translate page number to entry identifier.
+     * Convenience function to translate offset to entry identifier and set next/previous entries.
      *
-     * @param  {number}       dataId       Data Id.
-     * @param  {number}       [pageNumber] Page number where to go
-     * @param  {number}       group        Group Id to get the entry.
-     * @return {Promise<any>}              Resolved when done.
+     * @param {number} dataId Data Id.
+     * @param {number} [offset] Offset of the entry.
+     * @param {number} [groupId] Group Id to get the entry.
+     * @return {Promise<any>} Resolved when done.
      */
-    protected setEntryIdFromPage(dataId: number, pageNumber?: number, group?: number): Promise<any> {
-        if (typeof pageNumber == 'number') {
-            return this.dataHelper.getPageInfoByPage(dataId, pageNumber, group).then((result) => {
-                this.entryId = result.entryId;
-                this.page = null;
-            });
+    protected setEntryIdFromOffset(dataId: number, offset?: number, groupId?: number): Promise<any> {
+        if (typeof offset != 'number') {
+            // Entry id passed as navigation parameter instead of the offset.
+            // We don't display next/previous buttons in this case.
+            this.nextOffset = null;
+            this.previousOffset = null;
+
+            return Promise.resolve();
         }
 
-        return Promise.resolve();
+        const perPage = AddonModDataProvider.PER_PAGE;
+        const page = Math.floor(offset / perPage);
+        const pageOffset = offset % perPage;
+
+        return this.dataProvider.getEntries(dataId, groupId, undefined, undefined, page, perPage).then((entries) => {
+            if (!entries || !entries.entries || !entries.entries.length || pageOffset >= entries.entries.length) {
+                return Promise.reject(null);
+            }
+
+            this.entryId = entries.entries[pageOffset].id;
+            this.previousOffset = offset > 0 ? offset - 1 : null;
+            if (pageOffset + 1 < entries.entries.length) {
+                // Not the last entry on the page;
+                this.nextOffset = offset + 1;
+            } else if (entries.entries.length < perPage) {
+                // Last entry of the last page.
+                this.nextOffset = null;
+            } else {
+                // Last entry of the page, check if there are more pages.
+                return this.dataProvider.getEntries(dataId, groupId, undefined, undefined, page + 1, perPage).then((entries) => {
+                    this.nextOffset = entries && entries.entries && entries.entries.length > 0 ? offset + 1 : null;
+                });
+            }
+        });
     }
 
     /**
diff --git a/src/addon/mod/data/providers/helper.ts b/src/addon/mod/data/providers/helper.ts
index 97f6ac5e2..a94879196 100644
--- a/src/addon/mod/data/providers/helper.ts
+++ b/src/addon/mod/data/providers/helper.ts
@@ -100,11 +100,12 @@ export class AddonModDataHelperProvider {
      * @param {string} template   Template HMTL.
      * @param {any[]}  fields     Fields that defines every content in the entry.
      * @param {any}    entry      Entry.
+     * @param {number} offset     Entry offset.
      * @param {string} mode       Mode list or show.
      * @param {any}    actions    Actions that can be performed to the record.
      * @return {string}           Generated HTML.
      */
-    displayShowFields(template: string, fields: any[], entry: any, mode: string, actions: any): string {
+    displayShowFields(template: string, fields: any[], entry: any, offset: number, mode: string, actions: any): string {
         if (!template) {
             return '';
         }
@@ -135,7 +136,7 @@ export class AddonModDataHelperProvider {
                     render = this.translate.instant('addon.mod_data.' + (entry.approved ? 'approved' : 'notapproved'));
                 } else {
                     render = '<addon-mod-data-action action="' + action + '" [entry]="entries[' + entry.id +
-                                ']" mode="' + mode + '" [database]="data"></addon-mod-data-action>';
+                                ']" mode="' + mode + '" [database]="data" [offset]="' + offset + '"></addon-mod-data-action>';
                 }
                 template = template.replace(replace, render);
             } else {
@@ -177,24 +178,6 @@ export class AddonModDataHelperProvider {
         };
     }
 
-    /**
-     * Fetch all entries and return it's Id
-     *
-     * @param  {number}    dataId          Data ID.
-     * @param  {number}    groupId         Group ID.
-     * @param  {boolean}   [forceCache]    True to always get the value from cache, false otherwise. Default false.
-     * @param  {boolean}   [ignoreCache]   True if it should ignore cached data (it will always fail in offline or server down).
-     * @param  {string}    [siteId]        Site ID. Current if not defined.
-     * @return {Promise<any>}              Resolved with an array of entry ID.
-     */
-    getAllEntriesIds(dataId: number, groupId: number, forceCache: boolean = false, ignoreCache: boolean = false, siteId?: string):
-            Promise<any> {
-        return this.dataProvider.fetchAllEntries(dataId, groupId, undefined, undefined, undefined, forceCache, ignoreCache, siteId)
-                .then((entries) => {
-            return entries.map((entry) => entry.id);
-        });
-    }
-
     /**
      * Returns the default template of a certain type.
      *
@@ -398,67 +381,6 @@ export class AddonModDataHelperProvider {
         });
     }
 
-    /**
-     * Get page info related to an entry.
-     *
-     * @param  {number}    dataId          Data ID.
-     * @param  {number}    entryId         Entry ID.
-     * @param  {number}    groupId         Group ID.
-     * @param  {boolean}   [forceCache]    True to always get the value from cache, false otherwise. Default false.
-     * @param  {boolean}   [ignoreCache]   True if it should ignore cached data (it will always fail in offline or server down).
-     * @param  {string}    [siteId]        Site ID. Current if not defined.
-     * @return {Promise<any>}              Containing page number, if has next and have following page.
-     */
-    getPageInfoByEntry(dataId: number, entryId: number, groupId: number, forceCache: boolean = false,
-            ignoreCache: boolean = false, siteId?: string): Promise<any> {
-        return this.getAllEntriesIds(dataId, groupId, forceCache, ignoreCache, siteId).then((entries) => {
-            const index = entries.findIndex((entry) => entry == entryId);
-
-            if (index >= 0) {
-                return {
-                    previousId: entries[index - 1] || false,
-                    nextId: entries[index + 1] || false,
-                    entryId: entryId,
-                    page: index + 1, // Parsed to natural language.
-                    numEntries: entries.length
-                };
-            }
-
-            return false;
-        });
-    }
-
-    /**
-     * Get page info related to an entry by page number.
-     *
-     * @param  {number}    dataId          Data ID.
-     * @param  {number}    page            Page number.
-     * @param  {number}    groupId         Group ID.
-     * @param  {boolean}   [forceCache]    True to always get the value from cache, false otherwise. Default false.
-     * @param  {boolean}   [ignoreCache]   True if it should ignore cached data (it will always fail in offline or server down).
-     * @param  {string}    [siteId]        Site ID. Current if not defined.
-     * @return {Promise<any>}              Containing page number, if has next and have following page.
-     */
-    getPageInfoByPage(dataId: number, page: number, groupId: number, forceCache: boolean = false,
-            ignoreCache: boolean = false, siteId?: string): Promise<any> {
-        return this.getAllEntriesIds(dataId, groupId, forceCache, ignoreCache, siteId).then((entries) => {
-            const index = page - 1,
-                entryId = entries[index];
-
-            if (entryId) {
-                return {
-                    previousId: entries[index - 1] || null,
-                    nextId: entries[index + 1] || null,
-                    entryId: entryId,
-                    page: page, // Parsed to natural language.
-                    numEntries: entries.length
-                };
-            }
-
-            return false;
-        });
-    }
-
     /**
      * Get a list of stored attachment files for a new entry. See $mmaModDataHelper#storeFiles.
      *
diff --git a/src/addon/mod/data/providers/show-link-handler.ts b/src/addon/mod/data/providers/show-link-handler.ts
index 1d30f33ea..3685df23e 100644
--- a/src/addon/mod/data/providers/show-link-handler.ts
+++ b/src/addon/mod/data/providers/show-link-handler.ts
@@ -65,7 +65,7 @@ export class AddonModDataShowLinkHandler extends CoreContentLinksHandlerBase {
                     }
 
                     if (params.mode && params.mode == 'single') {
-                        pageParams['page'] = page || 1;
+                        pageParams['offset'] = page || 0;
                     } else if (rId) {
                         pageParams['entryId'] = rId;
                     }