diff --git a/src/addon/mod/wiki/pages/edit/edit.ts b/src/addon/mod/wiki/pages/edit/edit.ts
index b64a0fbe5..0a7dfdc14 100644
--- a/src/addon/mod/wiki/pages/edit/edit.ts
+++ b/src/addon/mod/wiki/pages/edit/edit.ts
@@ -482,8 +482,7 @@ export class AddonModWikiEditPage implements OnInit, OnDestroy {
                                 pageId: this.pageId,
                                 subwikiId: this.subwikiId,
                                 pageTitle: title,
-                                siteId: this.sitesProvider.getCurrentSiteId()
-                            });
+                            }, this.sitesProvider.getCurrentSiteId());
                         });
                     } else {
                         // Page stored in offline. Go to see the offline page.
diff --git a/src/addon/mod/workshop/components/index/index.ts b/src/addon/mod/workshop/components/index/index.ts
index ecbb91bbf..dbe91b367 100644
--- a/src/addon/mod/workshop/components/index/index.ts
+++ b/src/addon/mod/workshop/components/index/index.ts
@@ -117,7 +117,7 @@ export class AddonModWorkshopIndexComponent extends CoreCourseModuleMainActivity
      * @param {any} data Data received by the event.
      */
     protected eventReceived(data: any): void {
-        if ((this.workshop && this.workshop.id === data.workshopid) || data.cmid === module.id) {
+        if ((this.workshop && this.workshop.id === data.workshopId) || data.cmId === this.module.id) {
             this.content && this.content.scrollToTop();
 
             this.loaded = false;
@@ -297,7 +297,7 @@ export class AddonModWorkshopIndexComponent extends CoreCourseModuleMainActivity
             if (task.code == 'submit' && this.canSubmit && ((this.access.creatingsubmissionallowed && !this.submission) ||
                     (this.access.modifyingsubmissionallowed && this.submission))) {
                 const params = {
-                    module: module,
+                    module: this.module,
                     access: this.access,
                     courseId: this.courseId,
                     submission: this.submission
diff --git a/src/addon/mod/workshop/pages/edit-submission/edit-submission.html b/src/addon/mod/workshop/pages/edit-submission/edit-submission.html
new file mode 100644
index 000000000..e03d7087c
--- /dev/null
+++ b/src/addon/mod/workshop/pages/edit-submission/edit-submission.html
@@ -0,0 +1,30 @@
+
+    
+        {{ 'addon.mod_workshop.editsubmission' | translate }}
+        
+            
+        
+    
+
+
+    
+        
+    
+    
+        
+    
+
diff --git a/src/addon/mod/workshop/pages/edit-submission/edit-submission.module.ts b/src/addon/mod/workshop/pages/edit-submission/edit-submission.module.ts
new file mode 100644
index 000000000..c49f5e606
--- /dev/null
+++ b/src/addon/mod/workshop/pages/edit-submission/edit-submission.module.ts
@@ -0,0 +1,33 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import { NgModule } from '@angular/core';
+import { IonicPageModule } from 'ionic-angular';
+import { TranslateModule } from '@ngx-translate/core';
+import { CoreComponentsModule } from '@components/components.module';
+import { CoreDirectivesModule } from '@directives/directives.module';
+import { AddonModWorkshopEditSubmissionPage } from './edit-submission';
+
+@NgModule({
+    declarations: [
+        AddonModWorkshopEditSubmissionPage,
+    ],
+    imports: [
+        CoreDirectivesModule,
+        CoreComponentsModule,
+        IonicPageModule.forChild(AddonModWorkshopEditSubmissionPage),
+        TranslateModule.forChild()
+    ],
+})
+export class AddonModWorkshopEditSubmissionPageModule {}
diff --git a/src/addon/mod/workshop/pages/edit-submission/edit-submission.ts b/src/addon/mod/workshop/pages/edit-submission/edit-submission.ts
new file mode 100644
index 000000000..213aebe00
--- /dev/null
+++ b/src/addon/mod/workshop/pages/edit-submission/edit-submission.ts
@@ -0,0 +1,395 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import { Component, OnInit, OnDestroy } from '@angular/core';
+import { IonicPage, NavParams, NavController } from 'ionic-angular';
+import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+import { TranslateService } from '@ngx-translate/core';
+import { CoreEventsProvider } from '@providers/events';
+import { CoreSitesProvider } from '@providers/sites';
+import { CoreSyncProvider } from '@providers/sync';
+import { CoreFileSessionProvider } from '@providers/file-session';
+import { CoreDomUtilsProvider } from '@providers/utils/dom';
+import { CoreTextUtilsProvider } from '@providers/utils/text';
+import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader';
+import { AddonModWorkshopProvider } from '../../providers/workshop';
+import { AddonModWorkshopHelperProvider } from '../../providers/helper';
+import { AddonModWorkshopOfflineProvider } from '../../providers/offline';
+
+/**
+ * Page that displays the workshop edit submission.
+ */
+@IonicPage({ segment: 'addon-mod-workshop-edit-submission' })
+@Component({
+    selector: 'page-addon-mod-workshop-edit-submission',
+    templateUrl: 'edit-submission.html',
+})
+export class AddonModWorkshopEditSubmissionPage implements OnInit, OnDestroy {
+
+    module: any;
+    courseId: number;
+    access: any;
+    submission: any;
+
+    title: string;
+    loaded = false;
+    component = AddonModWorkshopProvider.COMPONENT;
+    componentId: number;
+    editForm: FormGroup; // The form group.
+
+    protected workshopId: number;
+    protected userId: number;
+    protected originalData: any = {};
+    protected hasOffline = false;
+    protected editing = false;
+    protected forceLeave = false;
+    protected siteId: string;
+    protected workshop: any;
+
+    constructor(navParams: NavParams, sitesProvider: CoreSitesProvider, protected fileUploaderProvider: CoreFileUploaderProvider,
+            protected workshopProvider: AddonModWorkshopProvider, protected workshopOffline: AddonModWorkshopOfflineProvider,
+            protected workshopHelper: AddonModWorkshopHelperProvider, protected navCtrl: NavController,
+            protected fileSessionprovider: CoreFileSessionProvider, protected syncProvider: CoreSyncProvider,
+            protected textUtils: CoreTextUtilsProvider, protected domUtils: CoreDomUtilsProvider, protected fb: FormBuilder,
+            protected translate: TranslateService, protected eventsProvider: CoreEventsProvider) {
+        this.module = navParams.get('module');
+        this.courseId = navParams.get('courseId');
+        this.access = navParams.get('access');
+        this.submission = navParams.get('submission') || {};
+
+        this.title = this.module.name;
+        this.workshopId = this.module.instance;
+        this.componentId = this.module.id;
+        this.userId = sitesProvider.getCurrentSiteUserId();
+        this.siteId = sitesProvider.getCurrentSiteId();
+
+        this.editForm = new FormGroup({});
+        this.editForm.addControl('title', this.fb.control('', Validators.required));
+        this.editForm.addControl('content', this.fb.control(''));
+    }
+
+    /**
+     * Component being initialized.
+     */
+    ngOnInit(): void {
+        this.fetchSubmissionData();
+    }
+
+    /**
+     * Check if we can leave the page or not.
+     *
+     * @return {boolean|Promise} Resolved if we can leave it, rejected if not.
+     */
+    ionViewCanLeave(): boolean | Promise {
+        if (this.forceLeave) {
+            return true;
+        }
+
+        let promise;
+
+        // Check if data has changed.
+        if (!this.hasDataChanged()) {
+            promise = Promise.resolve();
+        } else {
+            // Show confirmation if some data has been modified.
+            promise = this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
+        }
+
+        return promise.then(() => {
+            if (this.submission.attachmentfiles) {
+                // Delete the local files from the tmp folder.
+                this.fileUploaderProvider.clearTmpFiles(this.submission.attachmentfiles);
+            }
+        });
+    }
+
+    /**
+     * Fetch the submission data.
+     *
+     * @return {Promise} Resolved when done.
+     */
+    protected fetchSubmissionData(): Promise {
+        return this.workshopProvider.getWorkshop(this.courseId, this.module.id).then((workshopData) => {
+            this.workshop = workshopData;
+
+            if (this.submission && this.submission.id > 0) {
+                this.editing = true;
+
+                return this.workshopHelper.getSubmissionById(this.workshopId, this.submission.id).then((submissionData) => {
+                    this.submission = submissionData;
+                    this.submission.text = submissionData.content;
+
+                    const canEdit = (this.userId == submissionData.authorid && this.access.cansubmit &&
+                        this.access.modifyingsubmissionallowed);
+                    if (!canEdit) {
+                        // Should not happen, but go back if does.
+                        this.forceLeavePage();
+
+                        return;
+                    }
+                });
+            } else if (!this.access.cansubmit || !this.access.creatingsubmissionallowed) {
+                // Should not happen, but go back if does.
+                this.forceLeavePage();
+
+                return;
+            }
+
+        }).then(() => {
+            return this.workshopOffline.getSubmissions(this.workshopId).then((submissionsActions) => {
+                if (submissionsActions && submissionsActions.length) {
+                    this.hasOffline = true;
+                    const actions = this.workshopHelper.filterSubmissionActions(submissionsActions, this.editing ?
+                        this.submission.id : false);
+
+                    return this.workshopHelper.applyOfflineData(this.submission, actions).then((offlineSubmission) => {
+                        this.submission.title = offlineSubmission.title;
+                        this.submission.text = offlineSubmission.content;
+                        this.submission.attachmentfiles = offlineSubmission.attachmentfiles;
+                    });
+                } else {
+                    this.hasOffline = false;
+                }
+            }).finally(() => {
+                this.originalData.title = this.submission.title;
+                this.originalData.content = this.submission.text;
+                this.originalData.attachmentfiles = [];
+
+                this.submission.attachmentfiles.forEach((file) => {
+                    let filename;
+                    if (file.filename) {
+                        filename = file.filename;
+                    } else {
+                        // We don't have filename, extract it from the path.
+                        filename = file.filepath[0] == '/' ? file.filepath.substr(1) : file.filepath;
+                    }
+
+                    this.originalData.attachmentfiles.push({
+                        filename : filename,
+                        fileurl: file.fileurl
+                    });
+                });
+            });
+        }).then(() => {
+            // Create the form group and its controls.
+            this.editForm.controls['title'].setValue(this.submission.title);
+            this.editForm.controls['content'].setValue(this.submission.content);
+
+            const submissionId = this.submission.id || 'newsub';
+            this.fileSessionprovider.setFiles(this.component,
+                this.workshopId + '_' + submissionId, this.submission.attachmentfiles || []);
+
+            this.loaded = true;
+        }).catch((message) => {
+            this.loaded = false;
+
+            this.domUtils.showErrorModalDefault(message, 'core.course.errorgetmodule', true);
+
+            this.forceLeavePage();
+        });
+    }
+
+    /**
+     * Force leaving the page, without checking for changes.
+     */
+    protected forceLeavePage(): void {
+        this.forceLeave = true;
+        this.navCtrl.pop();
+    }
+
+    /**
+     * Get the form input data.
+     *
+     * @return {any} Object with all the info.
+     */
+    protected getInputData(): any {
+        const submissionId = this.submission.id || 'newsub';
+
+        const values = this.editForm.value;
+        values['attachmentfiles'] = this.fileSessionprovider.getFiles(this.component, this.workshopId + '_' + submissionId) || [];
+
+        return values;
+    }
+
+    /**
+     * Check if data has changed.
+     *
+     * @return {boolean} True if changed or false if not.
+     */
+    protected hasDataChanged(): boolean {
+        if (!this.loaded) {
+            return false;
+        }
+
+        const inputData = this.getInputData();
+        if (!this.originalData || typeof this.originalData.title == 'undefined') {
+            // There is no original data, assume it hasn't changed.
+            return false;
+        }
+
+        if (this.originalData.title != inputData.title || this.originalData.content != inputData.content) {
+            return true;
+        }
+
+        return this.fileUploaderProvider.areFileListDifferent(inputData.attachmentfiles, this.originalData.attachmentfiles);
+    }
+
+    /**
+     * Pull to refresh.
+     *
+     * @param {any} refresher Refresher.
+     */
+    refreshSubmission(refresher: any): void {
+        if (this.loaded) {
+            const promises = [];
+
+            promises.push(this.workshopProvider.invalidateSubmissionData(this.workshopId, this.submission.id));
+            promises.push(this.workshopProvider.invalidateSubmissionsData(this.workshopId));
+
+            Promise.all(promises).finally(() => {
+                return this.fetchSubmissionData();
+            }).finally(() => {
+                refresher.complete();
+            });
+        }
+    }
+
+    /**
+     * Save the submission.
+     */
+    save(): void {
+        // Check if data has changed.
+        if (this.hasDataChanged()) {
+            this.saveSubmission().then(() => {
+                // Go back to entry list.
+                this.forceLeavePage();
+            }).catch(() => {
+                // Nothing to do.
+            });
+        } else {
+            // Nothing to save, just go back.
+            this.forceLeavePage();
+        }
+    }
+
+    /**
+     * Send submission and save.
+     *
+     * @return {Promise} Resolved when done.
+     */
+    protected saveSubmission(): Promise {
+        const inputData = this.getInputData();
+
+        if (!inputData.title) {
+            this.domUtils.showAlert('core.notice', 'core.requireduserdatamissing');
+
+            return Promise.reject(null);
+        }
+        if (!inputData.content) {
+            this.domUtils.showAlert('core.notice', 'addon.mod_workshop.submissionrequiredcontent');
+
+            return Promise.reject(null);
+        }
+
+        let allowOffline = true,
+            saveOffline = false;
+
+        const modal = this.domUtils.showModalLoading('core.sending', true),
+            submissionId = this.submission && (this.submission.id || this.submission.submissionid) || false;
+
+        // Check if rich text editor is enabled or not.
+        return this.domUtils.isRichTextEditorEnabled().then((rteEnabled) => {
+            if (rteEnabled) {
+                inputData.content = this.textUtils.restorePluginfileUrls(inputData.content, this.submission.inlinefiles);
+            } else {
+                // Rich text editor not enabled, add some HTML to the message if needed.
+                inputData.content = this.textUtils.formatHtmlLines(inputData.content);
+            }
+
+            // Upload attachments first if any.
+            allowOffline = !inputData.attachmentfiles.length;
+
+            return this.workshopHelper.uploadOrStoreSubmissionFiles(this.workshopId, submissionId, inputData.attachmentfiles,
+                    this.editing, saveOffline).catch(() => {
+                // Cannot upload them in online, save them in offline.
+                saveOffline = true;
+                allowOffline = true;
+
+                return this.workshopHelper.uploadOrStoreSubmissionFiles(this.workshopId, submissionId, inputData.attachmentfiles,
+                    this.editing, saveOffline);
+            });
+        }).then((attachmentsId) => {
+            if (this.editing) {
+                if (saveOffline) {
+                    // Save submission in offline.
+                    return this.workshopOffline.saveSubmission(this.workshopId, this.courseId, inputData.title,
+                            inputData.content, attachmentsId, submissionId, 'update').then(() => {
+                        // Don't return anything.
+                    });
+                }
+
+                // Try to send it to server.
+                // Don't allow offline if there are attachments since they were uploaded fine.
+                return this.workshopProvider.updateSubmission(this.workshopId, submissionId, this.courseId, inputData.title,
+                    inputData.content, attachmentsId, undefined, allowOffline);
+            }
+
+            if (saveOffline) {
+                // Save submission in offline.
+                return this.workshopOffline.saveSubmission(this.workshopId, this.courseId, inputData.title, inputData.content,
+                    attachmentsId, submissionId, 'add').then(() => {
+                    // Don't return anything.
+                });
+            }
+
+            // Try to send it to server.
+            // Don't allow offline if there are attachments since they were uploaded fine.
+            return this.workshopProvider.addSubmission(this.workshopId, this.courseId, inputData.title, inputData.content,
+                attachmentsId, undefined, submissionId, allowOffline);
+        }).then((newSubmissionId) => {
+            const data = {
+                workshopId: this.workshopId,
+                cmId: this.module.cmid
+            };
+
+            if (newSubmissionId && submissionId) {
+                // Data sent to server, delete stored files (if any).
+                this.workshopOffline.deleteSubmissionAction(this.workshopId, submissionId, this.editing ? 'update' : 'add');
+                this.workshopHelper.deleteSubmissionStoredFiles(this.workshopId, submissionId, this.editing);
+                data['submissionId'] = newSubmissionId;
+            }
+
+            const promise = newSubmissionId ? this.workshopProvider.invalidateSubmissionData(this.workshopId, newSubmissionId) :
+                Promise.resolve();
+
+            return promise.finally(() => {
+                this.eventsProvider.trigger(AddonModWorkshopProvider.SUBMISSION_CHANGED, data, this.siteId);
+
+                // Delete the local files from the tmp folder.
+                this.fileUploaderProvider.clearTmpFiles(inputData.attachmentfiles);
+            });
+        }).catch((message) => {
+            this.domUtils.showErrorModalDefault(message, 'Cannot save submission');
+        }).finally(() => {
+            modal.dismiss();
+        });
+    }
+
+    /**
+     * Component being destroyed.
+     */
+    ngOnDestroy(): void {
+        this.syncProvider.unblockOperation(this.component, this.workshopId);
+    }
+}
diff --git a/src/addon/mod/workshop/providers/workshop.ts b/src/addon/mod/workshop/providers/workshop.ts
index 9962b836d..27660ef6f 100644
--- a/src/addon/mod/workshop/providers/workshop.ts
+++ b/src/addon/mod/workshop/providers/workshop.ts
@@ -215,10 +215,9 @@ export class AddonModWorkshopProvider {
 
             return site.read('mod_workshop_get_workshops_by_courses', params, preSets).then((response) => {
                 if (response && response.workshops) {
-                    for (const x in response.workshops) {
-                        if (response.workshops[x][key] == value) {
-                            return response.workshops[x];
-                        }
+                    const workshopFound = response.workshops.find((workshop) => workshop[key] == value);
+                    if (workshopFound) {
+                        return workshopFound;
                     }
                 }