Sorting BIM 360Issues through Forge - autodesk-forge

So I am working on this sample of forge: https://github.com/Autodesk-Forge/bim360-csharp-issues
I am struggling to sort the issues portrayed within the PropertyPanel. I am asking how I should go about doing this as I'm unsure?
Currently the sample loads your BIM36O document with the viewer, on the viewer there is an extension which when clicked shows all the issues one by one.
These issues are currently sorted by (Issue1,Issue2,Issue3).
I have manually used this line of code to sort the issues before they're shown on the panel:
_this.issues = _.sortBy(_this.issues, function (i) { return i.attributes.title });
I have also introduced panel buttons with onclick events, how do I sort the issues once the button is clicked and reshow the now sorted issues on the panel?
Here is my code for the panel:
function BIM360IssuePanel(viewer, container, id, title, options) {
this.viewer = viewer;
Autodesk.Viewing.UI.PropertyPanel.call(this, container, id, title, options);
var _this = this;
this.scrollContainer.style.height = 'calc(100% - 100px)';
const controlsContainer = document.createElement('div');
controlsContainer.classList.add('docking-panel-container-solid-color-a');
controlsContainer.style.height = '30px';
controlsContainer.style.padding = '4px';
const titleButton = document.createElement('button');
const assignedToButton = document.createElement('button');
const dueDateButton = document.createElement('button');
const createdAtButton = document.createElement('button');
const versionButton = document.createElement('button');
titleButton.innerText = 'Title';
versionButton.innerText = 'Version';
assignedToButton.innerText = 'Assigned To';
dueDateButton.innerText = 'Due Date';
createdAtButton.innerText = 'Created At';
titleButton.style.color = 'black';
versionButton.style.color = 'black';
assignedToButton.style.color = 'black';
dueDateButton.style.color = 'black';
createdAtButton.style.color = 'black';
controlsContainer.appendChild(titleButton);
controlsContainer.appendChild(versionButton);
controlsContainer.appendChild(assignedToButton);
controlsContainer.appendChild(dueDateButton);
controlsContainer.appendChild(createdAtButton);
this.container.appendChild(controlsContainer);
assignedToButton.onclick = function (e) {
};
titleButton.onclick = function (e) {
};
createdAtButton.onclick = function (e) {
};
dueDateButton.onclick = function (e) {
};
versionButton.onclick = function (e) {
};
}
Code for showIssues():
BIM360IssueExtension.prototype.showIssues = function () {
var _this = this;
//remove the list of last time
var pushPinExtension = _this.viewer.getExtension(_this.pushPinExtensionName);
pushPinExtension.removeAllItems();
pushPinExtension.showAll();
var selected = getSelectedNode();
//sorting issues
_this.issues = _.sortBy(_this.issues, function (i) { return i.attributes.title });
//_this.issues = _.sortBy(_this.issues, function (i) { if (i.attributes.due_date === null) return ''; else return Date.parse(i.attributes.due_date) });
//_this.issues = _.sortBy(_this.issues, function (i) { return i.attributes.assigned_to_name });
//_this.issues = _.sortBy(_this.issues, function (i) { return i.attributes.starting_version });
// _this.issues = _.sortBy(_this.issues, function (i) { return i.attributes.dateCreated });
_this.issues.forEach(function (issue) {
var dateCreated = moment(issue.attributes.created_at);
// show issue on panel
if (_this.panel) {
_this.panel.addProperty('Title', issue.attributes.title, 'Issue ' + issue.attributes.identifier);
_this.panel.addProperty('Assigned to', issue.attributes.assigned_to_name, 'Issue ' + issue.attributes.identifier);
_this.panel.addProperty('Version', 'V' + issue.attributes.starting_version + (selected.version != issue.attributes.starting_version ? ' (Not current)' : ''), 'Issue ' + issue.attributes.identifier)
_this.panel.addProperty('Due Date', issue.attributes.due_date, 'Issue ' + issue.attributes.identifier);
_this.panel.addProperty('Created at', dateCreated.format('MMMM Do YYYY, h:mm a'), 'Issue ' + issue.attributes.identifier);
}
// add the pushpin
var issueAttributes = issue.attributes;
var pushpinAttributes = issue.attributes.pushpin_attributes;
if (pushpinAttributes) {
issue.type = issue.type.replace('quality_', ''); // temp fix during issues > quality_issues migration
pushPinExtension.createItem({
id: issue.id,
label: issueAttributes.identifier,
status: issue.type && issueAttributes.status.indexOf(issue.type) === -1 ? `${issue.type}-${issueAttributes.status}` : issueAttributes.status,
position: pushpinAttributes.location,
type: issue.type,
objectId: pushpinAttributes.object_id,
viewerState: pushpinAttributes.viewer_state
});
}
})
}

Just did a quick check with the source code, there are 2 quick ideas:
If there would be some updates to issues while clicking the sort button, I would suggest to add a status of current sort order(sortOrder), and sorting the issues with different ways depending on sortOrder in the method showIssues, while clicking the different sort buttons, you may just call the BIM360IssueExtension.prototype.loadIssues() method to refresh all the issues in panel.
If the issue list would not be updated while clicking the sort button, I would suggest to cache the current issue list, and add a new method like sortIssueInPanel() to sort button, the main steps should be cleaning up the Issue Panel, sort the cached issue list, and add these issues one by one to the Issue Panel, the sample code snip should be something as follow, but be noted that's just code snip to show the main steps, i did not test or verify it, just for your reference:
var sortIssueInPanel = function(sortOrder){
var issueExtension = NOP_VIEWER.getExtension('BIM360IssueExtension');
issueExtension.panel.removeAllProperties()
// Sort the cached issues by sortOrder
switch(sortOrder){
case SORT_ORDER.BY_TITLE:
issuesCached = _.sortBy(issuesCached, function (i) { return i.attributes.title });
break;
case SORT_ORDER.BY_DUE_DATE:
issuesCached = _.sortBy(issuesCached, function (i) { if (i.attributes.due_date === null) return ''; else return Date.parse(i.attributes.due_date) });
break;
case SORT_ORDER.BY_ASSIGNED_TO_NAME:
issuesCached = _.sortBy(issuesCached, function (i) { return i.attributes.assigned_to_name });
break;
case SORT_ORDER.BY_DATECREATED:
issuesCached = _.sortBy(issuesCached, function (i) { return i.attributes.dateCreated });
break;
default:
break;
}
issuesCached.forEach(function (issue) {
var dateCreated = moment(issue.attributes.created_at);
// show issue on panel
if (issueExtension.panel) {
issueExtension.panel.addProperty('Title', issue.attributes.title, 'Issue ' + issue.attributes.identifier);
issueExtension.panel.addProperty('Assigned to', issue.attributes.assigned_to_name, 'Issue ' + issue.attributes.identifier);
issueExtension.panel.addProperty('Version', 'V' + issue.attributes.starting_version + (selected.version != issue.attributes.starting_version ? ' (Not current)' : ''), 'Issue ' + issue.attributes.identifier)
issueExtension.panel.addProperty('Due Date', issue.attributes.due_date, 'Issue ' + issue.attributes.identifier);
issueExtension.panel.addProperty('Created at', dateCreated.format('MMMM Do YYYY, h:mm a'), 'Issue ' + issue.attributes.identifier);
}
})
};
Hope it helps.

Related

Events to listen to before updating camera

Updating camera and target based on dbid of a selected node. The code starts with MobileVR function. I am updating camera and target according to frag mesh retrieved with dbid and then moving to VR mode. Currently I have an event listeners for GEOMETRY_LOADED_EVENT, OBJECT_TREE_CREATED_EVENT and EXTENSION_LOADED_EVENT. Currently it works with using a timeout setTimeout(() => { onSpaceObjectTreeCreated(); }, 3000); see image 1, but not without the the timeout image 2. Is there some other event that I should wait before running the code or updating the camera?
function onSpaceObjectTreeCreated() {
const nav = viewer.navigation;
const cam = nav.getCamera();
const it = viewer.model.getData().instanceTree;
let xPos, yPos, zPos;
it.enumNodeFragments(nodeId, (frag) => {
const mesh = viewer.impl.getRenderProxy(viewer.model, frag);
xPos = mesh.matrixWorld.elements[12];
yPos = mesh.matrixWorld.elements[13];
zPos = mesh.matrixWorld.elements[14];
console.log('x: ' + xPos + ' y: ' + yPos + ' z: ' + zPos);
}, false);
zPos = -41000;
cam.position.set(xPos, yPos, zPos);
cam.target.set(xPos, yPos + 10000, zPos);
}
function onViewerGeometryLoaded() {
const nav = viewer.navigation;
const cam = nav.getCamera();
if (nodeId == -1) {
viewer.setGroundShadow(false);
let xValue = viewer.getCamera().position.x;
let yValue = viewer.getCamera().position.y;
let zValue = viewer.getCamera().position.z;
let bbz = viewer.model.getData().bbox.min.z;
let zValue2 = zValue - bbz;
zValue = zValue * 0.3;
yValue = (zValue2 * 0.7071) * -1;
let nav = viewer.navigation;
let cam = viewer.getCamera();
cam.position.set(xValue, yValue, zValue);
} else {
setTimeout(() => {
onSpaceObjectTreeCreated();
}, 3000);
}
viewer.impl.sceneUpdated();
viewer.navigation.updateCamera();
document.getElementById("toolbar-vrTool").click();
};
function afterViewerEvents() {
var events = [
Autodesk.Viewing.GEOMETRY_LOADED_EVENT,
Autodesk.Viewing.OBJECT_TREE_CREATED_EVENT,
Autodesk.Viewing.EXTENSION_LOADED_EVENT
];
async.each(events,
function (event, callback) {
var handler = function (ev) {
viewer.removeEventListener(
event, handler);
console.log('Event: ' + event);
console.log('Ev: ' + ev.extensionId);
callback();
};
viewer.addEventListener(
event, handler);
},
function (err) {
onViewerGeometryLoaded();
});
}
function mobileVR(arkUrn: string, lviUrn: string, zOffset: number, spaceId: number) {
let element = document.getElementById("mobileViewer");
viewer = new Autodesk.Viewing.Private.GuiViewer3D(element);
let options = {
'env': 'AutodeskProduction',
'getAccessToken': getToken,
'refreshToken': getToken
};
av.Initializer(
options,
() => {
viewer.initialize();
loadDocument(arkUrn, zOffset);
if (lviUrn != "") {
loadDocument(lviUrn, zOffset);
}
viewer.loadExtension('Autodesk.Viewing.WebVR');
}
);
nodeId = spaceId;
afterViewerEvents();
}
Try to hookup the events after initializing the viewer and before loading the document:
viewer.initialize();
afterViewerEvents();
loadDocument(arkUrn, zOffset);
Also I don't get why you are using Autodesk.Viewing.EXTENSION_LOADED_EVENT, several extensions are being loaded automatically by the viewer upon startup or model loading, this event will be fired multiple times. If you are looking for a specific extension being loaded you need to check the extensionId and remove the handler only if this is the extension you are waiting for...
Hope that helps

Alexa (Expecting 'STRING', 'NUMBER', 'NULL', 'TRUE', 'FALSE', '{', '[', got 'undefined')

My code is not working when I test it in Amazon Developer and I don't see anything wrong with my code. It says my response is invalid.
Here's the code I tried to run but failed(I ran one response but not the other):
var Alexa = require('alexa-sdk');
exports.handler = function(event, context, callback) {
var alexa = Alexa.handler(event, context);
// alexa.dynamoDBTableName = 'YourTableName'; // creates new table for userid:session.attributes
alexa.registerHandlers(handlers);
alexa.execute();
};
var handlers = {
'LaunchRequest': function () {
this.emit('WelcomeIntent');
},
'WelcomeIntent': function () {
this.emit(':ask', 'Welcome to the guessing game! What difficulty would you like to play? Easy, Medium, or Hard?');
},
//------------------------------------------------------------------------------------------------------------------------------------------------
'DifficultyIntent': function (){
var difficulty = this.event.request.intent.slots.difficulty.value;
var range = 10; this.attributes['RandomNumberEnd'] = range;
if (difficulty === 'easy')
{ range = 10;
this.emit[':ask Your range is 1 - ' + range]
}
else if (difficulty === 'medium')
{ range = 100;
this.emit[':ask Your range is 1 - ' + range]
}
else (difficulty === 'hard');
{ range = 1000;
this.emit[':ask Your range is 1 - ' + range]
}
var randomNumber = Math.floor((Math.random()*range)+1);
var rightAnswer = this.attributes['rightAnswer'] = rightAnswer;
}, //check the user's guess with the right answer
'UserGuessIntent': function (){
var guess = this.event.request.intent.slots.guess.value;
this.attributes['guess'] = guess;
this.emit('CheckIntent'); },
'CheckIntent': function (){
var guess = this.attributes['guess'];
this.attributes['rightAnswer'] = randomNumber;
if(guess < rightAnswer){
this.emit(':ask', 'Try Again! Guess higher!');
}
else if(guess > rightAnswer)
{this.emit(':ask', 'Try Again! Guess lower!');
}
else{
this.emit(':tell', 'You are correct! Congratulations!');
}
},
'QuitIntent': function(){
var stop = this.event.request.intent.slots.stop.value;
this.emit('AMAZON.StopIntent');
},
'AMAZON.StopIntent' : function(){
var rightAnswer = this.attributes['rightAnswer'];
this.emit(':tell', 'The right answer is ' + rightAnswer + '. Goodbye!');
}
};

Funky IE JSON conversions

When running our AngularJS app in IE11 everything looks great in the debugger, but when our app encodes the data as JSON to save to our database, we get bad results.
Our app obtains a record from our database, then some manipulation is done and then the data is saved back to the server from another model.
Here is the data I got back from the server in the setAttendanceGetSInfo() function below:
{"data":{"Start":"2014-10-16T19:36:00Z","End":"2014-10-16T19:37:00Z"},
This is the code used to "convert the data" to 3 properties in our model:
var setAttendanceGetSInfo = function (CourseId, PID) {
return setAttendanceInfo(CourseId, PID)
.then(function (result) {
return $q.all([
$http.get("../api/Axtra/getSInfo/" + model.event.Id),
$http.get("../api/Axtra/GetStartAndEndDateTime/" + aRow.Rid)
]);
}).then(function (result) {
var r = result.data;
var e = Date.fromISO(r.Start);
var f = Date.fromISO(r.End);
angular.extend(model.event, {
examDate: new Date(e).toLocaleDateString(),
examStartTime: (new Date(e)).toLocaleTimeString(),
examEndTime: (new Date(f)).toLocaleTimeString()
});
return result.sInfo;
});
};
fromISO is defined as:
(function(){
var D= new Date('2011-06-02T09:34:29+02:00');
if(!D || +D!== 1307000069000){
Date.fromISO= function(s){
var day, tz,
rx=/^(\d{4}\-\d\d\-\d\d([tT ][\d:\.]*)?)([zZ]|([+\-])(\d\d):(\d\d))?$/,
p= rx.exec(s) || [];
if(p[1]){
day= p[1].split(/\D/);
for(var i= 0, L= day.length; i<L; i++){
day[i]= parseInt(day[i], 10) || 0;
};
day[1]-= 1;
day= new Date(Date.UTC.apply(Date, day));
if(!day.getDate()) return NaN;
if(p[5]){
tz= (parseInt(p[5], 10)*60);
if(p[6]) tz+= parseInt(p[6], 10);
if(p[4]== '+') tz*= -1;
if(tz) day.setUTCMinutes(day.getUTCMinutes()+ tz);
}
return day;
}
return NaN;
}
}
else{
Date.fromISO= function(s){
return new Date(s);
}
}
})()
Take a look at the screenshot of the event model data:
But, if I eval the event model using JSON.stringify(model.event), I get this:
{\"examDate\":\"?10?/?16?/?2014\",\"examStartTime\":\"?2?:?44?:?00? ?PM\",\"examEndTime\":\"?2?:?44?:?00? ?PM\"}
And this is the JSON encoded data that actually got stored on the DB:
"examDate":"¿10¿/¿16¿/¿2014","examStartTime":"¿2¿:¿36¿:¿00¿ ¿PM","examEndTime":"¿2¿:¿37¿:¿00¿ ¿PM"
What is wrong here and how can I fix this? It works exactly as designed in Chrome and Firefox. I have not yet tested on Safari or earlier versions of IE.
The toJSON for the date class isn't defined perfectly the same for all browsers.
(You can see a related question here: Discrepancy in JSON.stringify of date values in different browsers
I would suspect that you have a custom toJSON added to the Date prototype since your date string doesn't match the standard and that is likely where your issue is. Alternatively, you can use the Date toJSON recommended in the above post to solve your issues.
First, I modified the fromISO prototype to this:
(function () {
var D = new Date('2011-06-02T09:34:29+02:00');
if (!D || +D !== 1307000069000) {
Date.fromISO = function (s) {
var D, M = [], hm, min = 0, d2,
Rx = /([\d:]+)(\.\d+)?(Z|(([+\-])(\d\d):(\d\d))?)?$/;
D = s.substring(0, 10).split('-');
if (s.length > 11) {
M = s.substring(11).match(Rx) || [];
if (M[1]) D = D.concat(M[1].split(':'));
if (M[2]) D.push(Math.round(M[2] * 1000));// msec
}
for (var i = 0, L = D.length; i < L; i++) {
D[i] = parseInt(D[i], 10);
}
D[1] -= 1;
while (D.length < 6) D.push(0);
if (M[4]) {
min = parseInt(M[6]) * 60 + parseInt(M[7], 10);// timezone not UTC
if (M[5] == '+') min *= -1;
}
try {
d2 = Date.fromUTCArray(D);
if (min) d2.setUTCMinutes(d2.getUTCMinutes() + min);
}
catch (er) {
// bad input
}
return d2;
}
}
else {
Date.fromISO = function (s) {
return new Date(s);
}
}
Date.fromUTCArray = function (A) {
var D = new Date;
while (A.length < 7) A.push(0);
var T = A.splice(3, A.length);
D.setUTCFullYear.apply(D, A);
D.setUTCHours.apply(D, T);
return D;
}
Date.toJSON = function (key) {
return isFinite(this.valueOf()) ?
this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z' : null;
};
})()
Then I added moment.js and formatted the dates when they get stored:
var SaveAffRow = function () {
// make sure dates on coursedate and event are correct.
var cd = model.a.courseDate;
var ed = model.event.examDate;
var est = model.event.examStartTime;
var eet = model.event.examEndTime;
model.a.courseDate = moment(cd).format("MM/DD/YYYY");
model.event.examDate = moment(ed).format("MM/DD/YYYY");
model.event.examStartTime = moment(est).format("MM/DD/YYYY hh:mm A");
model.event.examEndTime = moment(eet).format("MM/DD/YYYY hh:mm A");
affRow.DocumentsJson = angular.toJson({a: model.a, event: model.event});
var aff = {};
if (affRow.Id != 0)
aff = affRow.$update({ Id: affRow.Id });
else
aff = affRow.$save({ Id: affRow.Id });
return aff;
};
and when they get read (just in case they are messed up already):
var setAttendanceGetSInfo = function (CourseId, PID) {
return setAttendanceInfo(CourseId, PID)
.then(function (result) {
return $q.all([
$http.get("../api/Axtra/getSInfo/" + model.event.Id),
$http.get("../api/Axtra/GetStartAndEndDateTime/" + aRow.Rid)
]);
}).then(function (result) {
var r = result.data;
var e = Date.fromISO(r.Start);
var f = Date.fromISO(r.End);
angular.extend(model.event, {
examDate: moment(e).format("MM/DD/YYYY"),
examStartTime: moment(e).format("MM/DD/YYYY hh:mm A"),
examEndTime: moment(f).format("MM/DD/YYYY hh:mm A")
});
return result.sInfo;
});
};

Why can't my html5 class find my observable array contents?

Thanks in advance for any help. I have spent a couple of weeks scouring the web for some insight. I have been developing code for over 50 years but I am a fairly new JavaScript, HTML, knockout. From what I see, this will be great if I can figure out how to make it work. The example given below is only one of the many things I have tried. Please advise.
I have defined two variables as observables, one computed observable, and one observableArray in my view model. Within the document.ready function, I make an Ajax call which returns a json in object notation. ( I checked it in the debugger). When my HTML page displays the observables and computed observables show up properly. The
observable array generates an error (see below) and then displays data obtained from only the first row returned from Ajax. (two were returned).
How do I adjust my code so that all the rows in the Ajax data are shown in the displayed HTML?
Here is the error message that I get:
Uncaught ReferenceError: Unable to process binding "foreach: function (){return cartItems }"
Message: Unable to process binding "text: function (){return itemSubTotal() }"
Message: itemSubTotal is not defined (19:41:39:172 | error, javascript)
Here is my global data for the view model:
var cartDB = "";
var totalPrice = "100";
var cartItems = new Array;
Here is the view model:
var ViewModel =function (){
// direct items ==
this.cartDB = ko.observable(cartDB);
// array itesm
// this.cartItems = ko.observableArray(cartItems);
this.cartItems = ko.mapping.fromJS(cartItems);
//for (var n = 1;n++;n<cartItems.length){ this.cartItems.push(cartItem[n]);}
// computed items
this.totalPriceSv = ko.computed(function(){
return "Total Price*=" + centsToDollars(totalPrice);// todo fix
} ,this);//end totalSvPrice
};// end ViewModel
The data is obtained from the following routine which calls on Ajax.This routine is called once from within document.ready and obtains the expected data on the success callback.
function databaseCart(commandInput, cartDBInput, cartPidInput,logPhpInput) {
var postData = new Array();
postData[0] = commandInput;
postData[1] = cartDBInput;
postData[2] = cartPidInput;
postData[3] = logPhpInput; //debug log on php side
data = null; //for return values
$.ajax({
type: "GET",
url: 'ww_CartProcess.php', //the script to call to get data
data: {data: postData},
dataType: 'json',
success: function(data) {
cartItems = data;
debug = 0;
},
complete: function(data) {
ko.applyBindings(new ViewModel);
return TRUE;
},
error: function(x, e) {//this is the error function for ajax
var xErr = x;
var eErr = e;
ajaxErrorProcessing(xErr, eErr, "addToCart", postData);
}
});
}// end databasecart
Here is the HTML 5 snippet.
<div>
<h1 id="cartTitle">Cart Number: <span data-bind="text: cartDB"> </h1>
<div class ="boxCartItem" data-bind="foreach:cartItems" >
<div class ="boxItemTitle">
<h2 data-bind="text: title()"></h2>
</div><!--boxItemTitle-->
<div class ="cartItemBottom"></div>
</div ><!--class ="boxCartItem"-->
My thanks to the commenters. I still do not know how to add an element to all item rows in an observable array, but this problem was caused by not having the item listed defined. Clue> When multiple errors are presented it is sometimes ( and maybe always) good to work from the bottom up.
The problem can be better stated as : Given a 2 x 17 array (2 rows and 17 columns of independent vars)create an observableArray that contains 2 rows and 17 plus columns consisting of the 17 independent variables (can only be changed in the database or by limited user input) augmented with a large number of computed functions .
1.0 I created an orderModel which contained the ko.computed(functions() for each dependent variable.
function rowOrder(data) {
var self = this;
var model = ko.mapping.fromJS(data, {}, self);
model.imagePathSv = ko.computed(function() {
var category = self.category();
var imageName = self.imageName();
var sv ="";
var sv = "products\\" +category+"\\" + imageName;
return sv;
});//end model.imagePathSv
//original offer
model.origNumValidate = ko.computed(function() {
ans = self.origNum();
if (ans < 0 | ans > 1) {
alert("\
Only onw Original can be pruchased");
ans = 1;
}
self.origNum(ans);
return ans;
});//originalNumValidate
model.origNumLabel = ko.computed(function() {
var sv = "Original..." + centsToDollars(self.origCost());
return sv;
});//end model.origNumLabel
model.origMattedShow = ko.computed(function() {
if (self.origMattedCost() > 0) {
return true;
}
else {
return false;
}
});
model.origMattedLabel = ko.computed(function() {
var sv = "Matting...." + centsToDollars(self.origMattedCost());
return sv;
});
model.origFramedShow = ko.computed(function() {
if (self.origFramedCost() > 0) {
return true;
}
else {
return false;
}
});
model.origFramedLabel = ko.computed(function() {
var sv = "Framing...." + centsToDollars(self.origFramedCost());
return sv;
});
//reproductons offer
model.reproNumValidate = ko.computed(function() {
ans = self.reproNum();
self.reproNum(ans);
return ans;
});
model.reproNumLabel = ko.computed(function() {
var sv = "Reproductions." + centsToDollars(self.reproCost()) + " each";
return sv;
});//end model.reproNumLabel
model.reproMattedShow = ko.computed(function() {
if (self.reproMattedCost() > 0) {
return true;
}
else {
return false;
}
});
model.reproMatted = ko.observable(true);
model.reproMattedLabel = ko.computed(function() {
var sv ="Matting...." +centsToDollars(self.reproMattedCost());
return sv;
});
model.reproFramedShow = ko.computed(function(){
if(self.reproFramedCost()>0){return true;}
else {return false;}
});
model.reproFramed = ko.observable(true);
model.reproFramedLabel = ko.computed(function() {
var sv ="Framing...." +centsToDollars(self.reproFramedCost());
return sv;
});
//pricing subTotals
model.productsSubTotal = ko.computed(function() {
var ans =self.origNum() * self.origCost() + self.reproNum() * self.reproCost();
return ans;
});//end model.productsSubTotal
model.productsSubTotalSv = ko.computed(function() {
return "Products.." +centsToDollars(model.productsSubTotal());
return ans;
});//end model.productsSubTotal
model.mattingSubTotal = ko.computed(function() {
return self.origNum() * self.origMattedCost() + self.reproNum() * self.reproMattedCost();
});//end model.mattingSubTotal
model.mattingSubTotalSv = ko.computed(function() {
return "Matting...." +centsToDollars(model.mattingSubTotal());
});//end model.mattingSubTotal
model.framingSubTotal = ko.computed(function() {
return self.origNum() * self.origFramedCost() + self.reproNum() * self.reproFramedCost();
});//end model.framingSubTotal
model.framingSubTotalSv = ko.computed(function() {
return "Framing...." +centsToDollars(model.framingSubTotal());
});//end model.productsSubTotal
model.rowSubTotal = ko.computed(function() {
return model.productsSubTotal() +model.mattingSubTotal() + model.framingSubTotal();
});//end model.rowsSubTotal
model.rowSubTotalSv = ko.computed(function() {
return "Item Subtotal.." +centsToDollars(model.rowSubTotal());
});//end model.productsSubTotal
};// END rowOrder
2.0 I created a mapping variable as follows:
var mapping = {
create: function(options) {
return new rowOrder(options.data);
}
};
3,0 I created a View Model as follows:
function ViewModel() {
// direct items for whole page
var self = this;
this.cartId = ko.observable(cartDB);
this.cartIdSv = ko.computed(function() {
var sv = "Cart Number: "+ self.cartId();
return sv;
},this);//
this.totalPrice = ko.computed(function() {//to DO COMPUTE
var int = 10000;
return int;
},this);
this.totalPriceSv = ko.computed(function(){
return "Total Price*: " + centsToDollars(this.totalPrice());
},this);
// by row items
this.cartItems = ko.mapping.fromJS(cartItems, mapping);
}// end ViewModel
4.0 In the success call back from ajax :
success: function(data) {
cartItems = data;
ViewModel();
5.0 I put the ko.apply.bindings(new ViewModel) in the ajax complete callback.
The result was that my rather involved page came up as expected with the computed values initially set.
I am still working on how to update this page. I have not been able to get my code to recompute the computed variables when the user clicks or unclicks a checkbox.
I could not have done this without suggestions from the stackOverflow group. Thanks to you all for the posts that I found all over the google.

jquery cookie code error

I tried to create a cookie for the link but it showed me errors like this....how to fix it...
Uncaught ReferenceError: createCookie is not defined
i am providing my code in fiidle
http://jsfiddle.net/SSMX4/82/ cookie not working
my jquery code is below
// locale selector actions
$('#region-picker').click(function(){
if ($("#locale-select").is(":visible")) return closeSelector('slide');
var foot_height = $('#footer').innerHeight();
var foot_height_css = foot_height-1;
var select_position = '-=' + (Number(700)+18);
console.log("hallo"+select_position);
var $selector = $('#locale-select');
$('#locale_pop').fadeOut();
$selector.css({top:foot_height_css});
$selector.fadeIn(function(){
$(this).addClass('open');
$(this).animate({top:select_position}, 1000);
});
});
$('#select-tab').click(function(e){
e.stopPropagation()
closeSelector('slide');
});
// don't hide when clicked within the box
$('#locale-select').click(function(e){
e.stopPropagation();
});
$(document).click(function(){
if ($('#locale-select').hasClass('open')) {
closeSelector('disappear');
}
});
$('.locale-link').click(function(){
//var $clicked = $(this); //"$(this)" and "this" is the clicked span
$(".locale-select-lable").html($(this).html());
//search for "marginXXXXX"
var flags = $(this).attr("class").match(/(margin\w+)\s/g);
//create new class; add matching value if found
var flagClass = "tk-museo-sans locale-select-lable" + (flags.length ? " " + flags[0] : "");
//set new class definition
$(".locale-select-lable").attr("class", flagClass);
closeSelector('disappear');
//if ($("#locale-select").is(":visible")) return closeSelector('slide');
/*
// var desired_locale = $(this).attr('rel');
// createCookie('desired-locale',desired_locale,360);
// createCookie('buy_flow_locale',desired_locale,360);
//closeSelector('disappear');
*/
}); /* CORRECTED */
$('#locale_pop a.close').click(function(){
var show_blip_count = readCookie('show_blip_count');
if (!show_blip_count) {
createCookie('show_blip_count',3,360);
}
else if (show_blip_count < 3 ) {
eraseCookie('show_blip_count');
createCookie('show_blip_count',3,360);
}
$('#locale_pop').slideUp();
return false;
});
function closeSelector(hide_type){
var foot_height = $('#footer').innerHeight();
var select_position = '+=' + (Number(400)+20);
if (hide_type == 'slide') {
$('#locale-select').animate({top:select_position}, 1000, function(){
$(this).removeClass('open');
$(this).fadeOut()
});
}
else if (hide_type == 'disappear'){
$('#locale-select').fadeOut('fast');
$('#locale-select').removeClass('open');
}
}
$('.locale-link').click(function(){
var desired_locale = $(this).attr('rel');
console.log("cookie....." + desired_locale);
createCookie('desired-locale',desired_locale,360);
createCookie('buy_flow_locale',desired_locale,360);
closeSelector('disappear');
})
$('#locale_pop a.close').click(function(){
var show_blip_count = readCookie('show_blip_count');
if (!show_blip_count) {
createCookie('show_blip_count',3,360);
}
else if (show_blip_count < 3 ) {
eraseCookie('show_blip_count');
createCookie('show_blip_count',3,360);
}
$('#locale_pop').slideUp();
return false;
});
​
I did not find your declaration of the function "createCookie". It seems you copied the code and forgot to copy the function.
Btw: "xxx is not defined" always means the variable/function does not exist ..