Show Modal in Durandal with BreezeJS

I have been struggling with this problem for a very long time and think why not ask about it here on Stackoverflow! My question is this:

I am creating a single page application (SPA) with Durandal and BreezeJS. Whenever the user creates something new, the createEntity function from Breeze Lib is called and I return my object. I insert this in Ko.observablearray and voila, it works fine;)

Before that, everything works fine.

But now the hard part comes in, I use ko.observablearray to create a data-bound table. Each line is clickable, and when you click on it, the SelectedMemo function is called and the "element" completes successfully. But here, when this function needs to create a custom modal, nothing happens. I get the error /app/views/.html does not exist. I know what is happening here, it is trying to redirect to a nonexistent page, because there is no View and model-view of the created object.

How to fix this problem? SO, that when I click a row in my table, I see all the data of my element?

This is the code so far:

VIew Model:

define(function (require) { var router = require('durandal/plugins/router'), app = require('durandal/app'), system = require('durandal/system'), addmemo = require('viewmodels/modals/addMemo'), memo = require('viewmodels/modals/memo'), //probably in the models folder but for now its okay dataservice = require('services/dataservice'), memos = ko.observableArray([]), suspendItemSave = false; function extendMemo(memoToExtend) { if (memoToExtend.isEditing) return; // already extended memoToExtend.isEditing = ko.observable(false); //Deze functie wordt getriggerd zodra het aanpassen klaar is! // listen for changes with Breeze PropertyChanged event memoToExtend.entityAspect.propertyChanged.subscribe(function () { if (memoToExtend.propertyChangedPending || suspendItemSave) { return; } // throttle property changed response // allow time for other property changes (if any) to come through memoToExtend.propertyChangedPending = true; setTimeout(validateAndSaveModifiedItem, 10); function validateAndSaveModifiedItem() { if (memoToExtend.entityAspect.entityState.isModified()) { if (memoToExtend.entityAspect.validateEntity()) { dataservice.saveChanges(); } else { // errors // handleItemErrors(memoToExtend); memoToExtend.isEditing(true); // go back to editing } } memoToExtend.propertyChangedPending = false; } }); } function init() { dataservice = new dataservice('api/memo'); dataservice.getAllRows('AllMemos').then(function (data) { data.results.forEach(function (item) { //Important step otherwise you are not able to create a memo modal! extendMemo(item); // memos.push(new memo(item)); memos.push(item); }); system.log("Initialization succesfull!"); }).fail(function() { system.log("Error initialization!"); }); } init(); return { displayName: 'Estimating page', memos: memos, activate: function() { system.log("Estimating page started!"); }, canDeactivate: function() { return app.showMessage('Are you sure you want to leave this page and stop estimating?', 'Navigate', ['Yes', 'No']); }, addMemo: function() { app.showModal(new addmemo()).then(function (result) { //maby first extend? For editing on the go see hot towel if (result != undefined) { var memoN = dataservice.createT({ Description: result[0].Description, CreationDate: result[0].CreationDate, Employee: result[0].User, Type: result[0].Type }, 'tblMemo'); if (memoN.entityAspect.validateEntity()) { extendMemo(memoN); //deze //memos.push(new memo(memoN)); //& deze moeten gewrapped worden!!! anders werkt de entityAspect niet memos.push(memoN); dataservice.saveChanges(); } /* if (memoN.entityAspect.validateEntity()) { //memos.push(memoN); //this is not the right thing to add this should be a memo Object! extendMemo(memoN); // extendMemo(newMemo); memos.push(new memo(memoN.Employee(), memoN.Description(), memoN.Type(), memoN.CreationDate())); dataservice.saveChanges(); }*/ } }).fail(function(result) { //in future show nice error message, hmmm toastr....? }); }, selectedMemo: function (selectedMemo, element) { //need to make a temp object with data before user clicks okay button or what so ever. //THis because the input fields are all observables if (selectedMemo) { selectedMemo.isEditing(true); } app.showModal(selectedMemo).then(function (result) { if (result) { if (selectedMemo) { selectedMemo.isEditing(false); memos.remove(selectedMemo); selectedMemo.entityAspect.setDeleted(); dataservice.saveChanges(); } } }).fail(function() { }); //futher use for deleting memo /* app.showMessage('Do you want to delete this memo?', 'Delete memo', ['Yes', 'No']).then(function (result) { if (result == "Yes") { memos.remove(selectedMemo); selectedMemo.entityAspect.setDeleted(); dataservice.saveChanges(); } }); */ } }; }); 

I also tried to create a Memo object, but when I do this, EntityAspect is lost in my element! But then does modal work? How to solve all this?

UPDATE 2:

I rewrote my Memo model so that it contains an object in a variable. But PropertyPendingChanged no longer starts: S

+4
source share
1 answer

SO I finally did it :) I coded it for 3 days, but I got it working!

Here is what I did with my code, I created Memo.js, which contains only a variable with an entity. In my opinion, I call this variable and my data. When the user edits the value, the subscription function starts automatically and the new value is transferred to the database. Hope this is helpful, took me 3 full days about 8 hours each XD

representation

memo.html

 <div class="messageBox"> <div class="modal-header"> <h2>Memo details</h2> </div> <div class="modal-body"> Employee: <input type="text" data-bind="value: MemoEntity._latestValue.Employee"/> Description: <input type="text" data-bind="value: MemoEntity._latestValue.Description"/> Type: <input type="text" data-bind="value: MemoEntity._latestValue.Type"/> </div> <div class="modal-footer"> <ul class="btn-group"> <button class="btn" data-bind="click: closeModal">Ok</button> <button class="btn btn-primary" data-bind="click: deleteMemo">Delete</button> </ul> </div> </div> 

Commemorative View Model

 (function () { var _this = this; //self.dataservice = require('services/dataservice'); define(function (require) { var Memo; return Memo = (function () { function Memo(dataForMemo) { this.MemoEntity = ko.observable(dataForMemo); // this.Employee = ko.observable(dataForMemo.entityAspect.entity.Employee()); // this.Description = ko.observable(dataForMemo.entityAspect.entity.Description()); // this.Type = ko.observable(dataForMemo.entityAspect.entity.Type()); // this.CreationDate = ko.observable(dataForMemo.entityAspect.entity.CreationDate()); // this.isEditing = dataForMemo.entityAspect.entity.isEditing; } Memo.prototype.closeModal = function () { return this.modal.close(false); }; Memo.prototype.deleteMemo = function () { return this.modal.close(true); }; return Memo; })(); }); }).call(this); 

And my js page

view model

 define(function (require) { var router = require('durandal/plugins/router'), app = require('durandal/app'), system = require('durandal/system'), addmemo = require('viewmodels/modals/addMemo'), memo = require('viewmodels/modals/memo'), //probably in the models folder but for now its okay dataservice = require('services/dataservice'), memos = ko.observableArray([]), suspendItemSave = false; function extendMemo(memoToExtend) { if (memoToExtend.isEditing) return; // already extended memoToExtend.isEditing = ko.observable(false); //Deze functie wordt getriggerd zodra het aanpassen klaar is! // listen for changes with Breeze PropertyChanged event memoToExtend.entityAspect.propertyChanged.subscribe(function () { if (memoToExtend.propertyChangedPending || suspendItemSave) { return; } // throttle property changed response // allow time for other property changes (if any) to come through memoToExtend.propertyChangedPending = true; setTimeout(validateAndSaveModifiedItem, 10); function validateAndSaveModifiedItem() { if (memoToExtend.entityAspect.entityState.isModified()) { if (memoToExtend.entityAspect.validateEntity()) { dataservice.saveChanges(); } else { // errors // handleItemErrors(memoToExtend); memoToExtend.isEditing(true); // go back to editing } } memoToExtend.propertyChangedPending = false; } }); } function init() { dataservice = new dataservice('api/memo'); dataservice.getAllRows('AllMemos').then(function (data) { data.results.forEach(function (item) { //Important step otherwise you are not able to create a memo modal! extendMemo(item); var t = new memo(item); memos.push(t); //memos.push(item); }); system.log("Initialization succesfull!"); }).fail(function() { system.log("Error initialization!"); }); } init(); return { displayName: 'Estimating page', memos: memos, activate: function() { system.log("Estimating page started!"); }, canDeactivate: function() { return app.showMessage('Are you sure you want to leave this page and stop estimating?', 'Navigate', ['Yes', 'No']); }, addMemo: function() { app.showModal(new addmemo()).then(function (result) { //maby first extend? For editing on the go see hot towel if (result != undefined) { var memoN = dataservice.createT({ Description: result[0].Description, CreationDate: result[0].CreationDate, Employee: result[0].User, Type: result[0].Type }, 'tblMemo'); if (memoN.entityAspect.validateEntity()) { extendMemo(memoN); //deze memos.push(new memo(memoN)); //& deze moeten gewrapped worden!!! anders werkt de entityAspect niet dataservice.saveChanges(); } /* if (memoN.entityAspect.validateEntity()) { //memos.push(memoN); //this is not the right thing to add this should be a memo Object! extendMemo(memoN); // extendMemo(newMemo); memos.push(new memo(memoN.Employee(), memoN.Description(), memoN.Type(), memoN.CreationDate())); dataservice.saveChanges(); }*/ } }).fail(function(result) { //in future show nice error message, hmmm toastr....? }); }, selectedMemo: function (selectedMemo, element) { //need to make a temp object with data before user clicks okay button or what so ever. //THis because the input fields are all observables // if (selectedMemo) { //selectedMemo.MemoEntity._latestValue.entity.isEditing(true); // selectedMemo.isEditing(true); // } app.showModal(selectedMemo).then(function (result) { if (result) { app.showMessage('Do you want to delete this memo?', 'Delete memo', ['Yes', 'No']).then(function (resultMes) { if (resultMes == "Yes") { memos.remove(selectedMemo); selectedMemo.MemoEntity._latestValue.entityAspect.setDeleted(); dataservice.saveChanges(); } }); } }).fail(function() { }); //futher use for deleting memo /* app.showMessage('Do you want to delete this memo?', 'Delete memo', ['Yes', 'No']).then(function (result) { if (result == "Yes") { memos.remove(selectedMemo); selectedMemo.entityAspect.setDeleted(); dataservice.saveChanges(); } }); */ } }; }); 

And my opinion with notes

 <table class="table table-hover table-striped"> <thead> <tr> <th>Created</th><th>User</th><th>Memo</th><th>Type</th> </tr> </thead> <tbody data-bind="visible: memos().length > 0, foreach: memos"> <tr data-bind="click: $parent.selectedMemo"> <td data-bind="text: MemoEntity._latestValue.CreationDate"></td> <td data-bind="text: MemoEntity._latestValue.Employee"></td> <td data-bind="text: MemoEntity._latestValue.Description"></td> <td data-bind="text: MemoEntity._latestValue.Type"></td> </tr> </tbody> <tbody data-bind="visible: memos().length == 0"> <tr> <td colspan="4">NO MEMOS ADDED YET</td> </tr> </tbody> </table> 

Hope this helps;)

+5
source

All Articles