Swipe to Reveal is not working - html

I have implemented a swipe to reveal Oracle JET component.
Below is my Js code
this.action = ko.observable("No action taken yet");
this.handleReady = function()
{
// register swipe to reveal for all new list items
$("#listview").find(".item-marker").each(function(index)
{
var item = $(this);
var id = item.prop("id");
var startOffcanvas = item.find(".oj-offcanvas-start").first();
var endOffcanvas = item.find(".oj-offcanvas-end").first();
// setup swipe actions
oj.SwipeToRevealUtils.setupSwipeActions(startOffcanvas);
oj.SwipeToRevealUtils.setupSwipeActions(endOffcanvas);
// make sure listener only registered once
endOffcanvas.off("ojdefaultaction");
endOffcanvas.on("ojdefaultaction", function()
{
self.handleDefaultAction(item);
});
});
};
this.handleDestroy = function()
{
// register swipe to reveal for all new list items
$("#listview").find(".item-marker").each(function(index)
{
var startOffcanvas = $(this).find(".oj-offcanvas-start").first();
var endOffcanvas = $(this).find(".oj-offcanvas-end").first();
oj.SwipeToRevealUtils.tearDownSwipeActions(startOffcanvas);
oj.SwipeToRevealUtils.tearDownSwipeActions(endOffcanvas);
});
};
this.handleMenuBeforeOpen = function(event, ui)
{
var target = event.originalEvent.target;
var context = $("#listview").ojListView("getContextByNode", target);
if (context != null)
{
self.currentItem = $("#"+context['key']);
}
else
{
self.currentItem = null;
}
};
this.handleMenuItemSelect = function(event, ui)
{
var id = ui.item.prop("id");
if (id == "read")
self.handleRead();
else if (id == "more1" || id == "more2")
self.handleMore();
else if (id == "tag")
self.handleFlag();
else if (id == "delete")
self.handleTrash();
};
this.closeToolbar = function(which, item)
{
var toolbarId = "#"+which+"_toolbar_"+item.prop("id");
var drawer = {"displayMode": "push", "selector": toolbarId};
oj.OffcanvasUtils.close(drawer);
};
this.handleAction = function(which, action, event)
{
if (event != null)
{
self.currentItem = $(event.target).closest(".item-marker");
// offcanvas won't be open for default action case
if (action != "default")
self.closeToolbar(which, self.currentItem);
}
if (self.currentItem != null)
self.action("Handle "+action+" action on: "+self.currentItem.prop("id"));
};
this.handleRead = function(data, event)
{
self.handleAction("first", "read", event);
};
this.handleMore = function(data, event)
{
self.handleAction("second", "more", event);
};
this.handleFlag = function(data, event)
{
self.handleAction("second", "Rejected", event);
};
this.handleTrash = function(data, event)
{
self.handleAction("second", "Accepted", event);
self.remove(self.currentItem);
};
this.handleDefaultAction = function(item)
{
self.currentItem = item;
self.handleAction("second", "default");
self.remove(item);
};
this.remove = function(item)
{
// unregister swipe to reveal for removed item
var startOffcanvas = item.find(".oj-offcanvas-start").first();
var endOffcanvas = item.find(".oj-offcanvas-end").first();
oj.SwipeToRevealUtils.tearDownSwipeActions(startOffcanvas);
oj.SwipeToRevealUtils.tearDownSwipeActions(endOffcanvas);
alert(JSON.stringify(self.allItems()));
alert(item.toString());
self.allItems.remove(function(current)
{
return (current.id == item.prop("id"));
});
};
}
return PeopleViewModel;
});
HTML code:
<ul id="listview"
data-bind="ojComponent: {component: 'ojListView',
data: listViewDataSource,
item: {template: 'peoplelist_template'},
selectionMode: 'single',
ready: handleReady,
destroy: handleDestroy,
optionChange: changeHandler,
rootAttributes: {style: 'width:100%;height:100vh;overflow:auto; margin-top: 5px'},
scrollPolicy: 'loadMoreOnScroll',
scrollPolicyOptions: {fetchSize: 10}}">
</ul>
<script id="peoplelist_template">
<div style="padding:0.8571rem">
<div class="oj-flex oj-flex-items-pad">
<div class="oj-flex-item oj-lg-4 oj-md-4">
<img alt="employee image" class="demo-circular demo-employee-photo" style="float:left;" data-bind="attr: {src: $parent.getPhoto($data['name'])}"/>
<h2 class="demo-employee-name" data-bind="text: $data['from']"></h2>
<div class="demo-employee-title" data-bind="text: $data['title']"></div>
<div class="demo-employee-dept" data-bind="text: $data['deptName']"></div>
</div>
<div style="line-height: 1.5em; height: 3em; overflow: hidden; text-overflow: ellipsis" class="oj-text-sm oj-text-secondary-color" data-bind="text: $data['content']"></div>
</div>
</div>
<div tabIndex="-1" data-bind="attr: {id: 'first_toolbar_'+empId}" class="oj-offcanvas-start" style="width:75px">
<div data-bind="click:$parent.handleRead">
<div class="oj-flex-bar" style="height:100%">
<div class="oj-flex-bar-center-absolute">
<div class="oj-flex oj-sm-flex-direction-column">
<div title=".demo-library-icon-24" role="img" class="oj-flex-item demo-library-icon-24 demo-icon-font-24"></div>
<div style="padding-top: 10px" class="oj-flex-item">Read</div>
</div>
</div>
</div>
</div>
</div>
<div tabIndex="-1" data-bind="attr: {id: 'second_toolbar_'+empId}" class="oj-offcanvas-end" style="width:225px">
<div class="oj-swipetoreveal-more" data-bind="click: $parent.handleMore">
<div class="oj-flex-bar" style="height:100%">
<div class="oj-flex-bar-center-absolute">
<div class="oj-flex oj-sm-flex-direction-column">
<div title=".demo-library-icon-24" role="img" class="oj-flex-item fa fa-bars"></div>
<div style="padding-top: 10px" class="oj-flex-item">More</div>
</div>
</div>
</div>
</div>
<div style="background-color:#b81900" data-bind="click: $parent.handleFlag" class="oj-swipetoreveal-flag">
<div class="oj-flex-bar" style="height:100%">
<div class="oj-flex-bar-center-absolute">
<div class="oj-flex oj-sm-flex-direction-column">
<div title=".demo-library-icon-24" role="img" class="oj-flex-item fa fa-times"></div>
<div style="padding-top: 10px" class="oj-flex-item">Reject</div>
</div>
</div>
</div>
</div>
<div style="background-color:#009638" data-bind="click: $parent.handleTrash" class="oj-swipetoreveal-alert oj-swipetoreveal-default">
<div class="oj-flex-bar" style="height:100%">
<div class="oj-flex-bar-center-absolute">
<div class="oj-flex oj-sm-flex-direction-column">
<div title=".demo-library-icon-24" role="img" class="oj-flex-item fa fa-check"></div>
<div style="padding-top: 10px" class="oj-flex-item">Approve</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</li>
</script>
Actual problem is the listItem is not getting removed while approving.(The Approve div is call Handletrash function).
I dont know where I went wrong ??could anyone help me to solve this issue??

There's a lot of code here, which makes it hard to understand what everything is intended to do, and harder to pinpoint what the problem might be. That's why it's best to make a Minimal, Complete, and Verifiable Example. Also, in the process of removing all the code that does not directly affect your problem, you may solve it yourself.
I notice in your code that you have a number of jQuery calls. That's a significant red flag. Your contract with Knockout is that you will manipulate your data model and Knockout will use it to control the DOM. If you "go behind Knockout's back" and manipulate the DOM yourself, you and Knockout are going to be stepping on each other's toes.
Knockout provides two ways for you to customize how it manipulates the DOM: animated transitions and custom bindings. "Swipe to reveal" sounds like a transition to me, but looking at your code, it appears there's a whole lifecycle involved, so I think you need to make a custom binding handler.
All of your DOM-manipulating code should be inside the binding handler, and all of it should be restricted to the element of the binding handler. There should be no document-wide selectors.

Related

Variable get different result inside and outside of object

I have one question. I am doing automatic slider with option to click on dot, which picture I want to show.
But I have problem with variable, which should find SVG and then I use this variable as a value for an array.
PROBLEM IS:
If I define this variable "dot" INSIDE of my object "Slider", it finds all SVG in div element.
But if I declare this variable "dot" OUTSIDE of my object, I will find elements instead of SVG.
Problematic part is:
dot = $('.images-switch').children(), - give different results if INSIDE or OUTSIDE of object SLIDER
Can you advise me how to solve it. And give my your opinion about my solution of slider?
Code is below (var dot is defined inside Slider object = find alls SVG):
var covers = $('.fadecovers'),
cover = $('.cover'),
imagesSwitch = $('.images-switch')
i = 0,
slideCount = $('.cover').length,
slide = $('.cover'),
slideArr = jQuery.makeArray(slide),
dot = $('.images-switch').children(),
dotArr = jQuery.makeArray(dot),
n = 0;
console.log(dot);
for (n = 0; n < (slideCount); n++) {
$(dotArr[n]).attr('data', n);
};
$('.images-switch').children().first().addClass('active');
//Zaciatok objektu
var Slider = {
// nastavenie atributov objektu Slider defaultne ako null
intervalID: null,
running: false,
start: function() {
intervalID = setInterval (function () {
var dot = $('.images-switch').children(),
dotArr = jQuery.makeArray(dot);
if (i == slideCount) {i = 0};
if (cover.eq(0).is(':visible')) {i = 1};
$(slideArr).fadeOut(700);
$(slideArr[i]).fadeIn(700);
$(dotArr).removeClass('active');
$(dotArr[i]).addClass('active')
i++;
running = true;
},3500);
},
pause: function() {
//stopne vykonavanie setInterval funkcie
clearInterval(intervalID);
intervalID = null;
running = false;
},
resume: function() {
//ak nie je interval prazdny (teda ako keby neexistuje), tak spusti vykonavanie setInterval funkcie
if (!intervalID) {this.start()};
},
//zlucenie funckii na stopnutie a znovu spustenie setInterval
toggle: function() {
if (running) this.pause();
else this.resume();
},
};
Slider.start();
covers.on('click', function() {
Slider.toggle();
});
imagesSwitch.on('click', 'svg', function() {
var dot = $('.images-switch').children(),
dotArr = jQuery.makeArray(dot),
data = $(this).attr('data');
i = data;
$(slideArr).fadeOut(700);
$(slideArr[i]).fadeIn(700);
$(dotArr).removeClass('active');
$(dotArr[i]).addClass('active')
i++;
});
Here is belonging HTML code:
<header class="article-header">
<div class="container">
<h1 class="post-title">
Naše portfólio prác
</h1>
</div>
<div class="fadecovers">
<div class="cover"><img src="img/dragon-1.jpg"></div>
<div class="cover fade-out" ><img src="img/dragon-2.jpg"></div>
<div class="cover fade-out"><img src="img/dragon-3.jpg"></div>
<div class="cover fade-out" ><img src="img/dragon-4.jpg"></div>
</div>
<div class="images-switch">
<i class="fas fa-circle"></i>
<i class="fas fa-circle"></i>
<i class="fas fa-circle"></i>
<i class="fas fa-circle"></i>
</div>
</header>
I finally solved it by myself. I changed the circles made by SVG to SPAN (circle made by CSS). Now it works.

Incorrect Get API call format JS knockout asp.net

I am new to writing web apps and this is the first time with Knockout
I am trying to build a URL for Get call to my API, which I know is works if I use a static URL. I trigger the Get call by clicking on the Details link.
My aim is to pass the current item and use it's indx property.
However I get the following
when I am try to get a URL of /api/ReqsTest/2 if I click on the item with a Index of 2
My mark up to call is
<small>Details</small>
My Knockout Function is
// Details
self.detail = ko.observable();
self.getReqDetail = function (item) {
var url = reqsUri + item.indx;
alert("Get Url :" + url);// just for debug
ajaxHelper(url, 'GET').done(function (data) {
self.detail(data);
}
);
Can some explain what I have got wrong and why please
My Full ViewModel code is
function ReqsTest(rt) {
rt = rt || {};
var self = this;
self.id = ko.observable(rt.ID || 0);
self.requisition = ko.observable(rt.Requisition || "");
self.reqnStatus = ko.observable(rt.ReqnStatus || "");
self.dateReqnRaised = ko.observable(rt.DateReqnRaised|| null);
self.reqnValue = ko.observable(rt.ReqnValue || null);
self.approvedValue = ko.observable(rt.ApprovedValue || null);
self.originator = ko.observable(rt.Originator || "");
self.origName = ko.observable(rt.OrigName || "");
self.origEmail = ko.observable(rt.OrigEmail || "");
self.line = ko.observable(rt.Line || 0.00);
self.indx = ko.observable(rt.INDX || 0);
self.dateReqnRaisedL = ko.observable(rt.DateReqnRaisedL || null);
self.reqStatus = ko.observable(rt.ReqStatus || "");
//self.reqBackground = ko.observable(rt.ReqBackground || "");
//Computed observables
self.reqBackground = ko.computed(function () {
// get variable
var status = self.reqStatus();
if (status == "A") { return "card-heading bg-success text-white"; }
else if (status == "D") { return "card heading bg-danger"; }
else {
return "card-heading bg-primary text-white";
}
})
self.reqStatusLabel = ko.computed(function () {
// get variable
var status = self.reqStatus();
if (status == "A") { return "Approved"; }
else if (status == "D") { return "Declined"; }
else {
return "Awaiting Approval";
}
})
}
function ReqsViewModel (){
var self = this;
self.Reqs = ko.observableArray([]);
self.error = ko.observable();
var reqsUri = '/api/ReqsTests/';
function ajaxHelper(uri, method, data) {
self.error(''); // Clear error message
return $.ajax({
type: method,
url: uri,
dataType: 'json',
contentType: 'application/json',
data: data ? JSON.stringify(data) : null
}).fail(function (jqXHR, textStatus, errorThrown) {
self.error(errorThrown);
});
}
function getAllReqs() {
ajaxHelper(reqsUri, 'GET').done(function (data) {
// Build the ReqsTest objects
var reqs = ko.utils.arrayMap(data, function (rt) {
return new ReqsTest(rt);
});
self.Reqs(reqs);
});
}
// Details
self.detail = ko.observable();
self.getReqDetail = function (item) {
var url = reqsUri + item.indx;
alert("Get Url :" + url);// just for debug
ajaxHelper(url, 'GET').done(function (data) {
self.detail(data);
}
);
}
//Approval function
self.Approval = function (item) {
item.reqStatus("A");
alert("Approval " + item.reqStatus);
}
// Load the reqs - Take this out if you don't want it
getAllReqs();
}
ko.applyBindings(new ReqsViewModel());
My full mark up is
#section scripts {
#Scripts.Render("~/bundles/app")
}
<div class="page-header">
<h1>Chamberlin Requistions</h1>
</div>
<div class="row">
<div class="col-xs-4">
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Requistions</h2>
</div>
<div class="panel-body panel-info ">
<ul class="list-unstyled" data-bind="foreach: Reqs">
<li>
<div class="card">
<div data-bind="css: reqBackground">
<strong>
<span data-bind="text: requisition"></span>
: <span data-bind="text: line"></span> <br />
Status: <span data-bind="text: reqStatusLabel"></span>
:Index: <span data-bind="text: indx"></span>
</strong>
</div>
<div class="card-body">
<p>
<span data-bind="text: dateReqnRaisedL"></span>
: <span data-bind="text: origName"></span>
:£ <span data-bind="text: reqnValue"></span>
<small>Details</small>
</p>
</div>
<div class="card-footer">
#* Buttons to go in here *#
<div class="btn-group btn-group-xs">
<button type="button" class="btn btn-primary" data-bind="click: $parent.Aprroval">Approve</button>
<button type="button" class="btn btn-primary">Decline</button>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#myModal">Unknown</button>
</div>
</div>
</div>
</li>
<p></p>
</ul>
</div>
</div>
<div class="alert alert-danger" data-bind="visible: error"><p data-bind="text: error"></p></div>
</div>
<!-- ko if:detail() -->
<div class="col-xs-4">
<div class="card bg-info">
<div class="card-header">
<h2 class="panel-title">Detail</h2>
</div>
<div class="card-body">
<table class="table">
<tr><td>Requistion</td><td data-bind="text: detail().Requisition"></td></tr>
<tr><td>Line</td><td data-bind="text: detail().Line"></td></tr>
<tr><td>Date Raised</td><td data-bind="text: detail().DateReqnRaisedL"></td></tr>
<tr><td>Requested Value</td><td data-bind="text: detail().ReqnValue"></td></tr>
<tr><td>Requestor Email</td><td data-bind="text: detail().OrigEmail"></td></tr>
</table>
</div>
</div>
</div>
<!-- /ko -->
#*<div class="col-xs-4">
TODO: Add new book
</div>*#
</div>
<!-- Modal -->
<div id="myModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Modal Header</h4>
</div>
<div class="modal-body">
<p>Some text in the modal.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
Well that was me forgetting the basic of Knockout
For the future remember to include the ()
So
var url = reqsUri + item.indx;
Becomes
var url = reqsUri + item.indx();
Corrected function
// Details
self.detail = ko.observable();
self.getReqDetail = function (item) {
var url = reqsUri + item.indx();
alert("Get Url :" + url);// just for debug
ajaxHelper(url, 'GET').done(function (data) {
self.detail(data);
}
);

Splitting up results of knockout data into 2 columns

Was curious if there was an easy way to split up the following code into 2 columns via Knockout and HTML. I know how to do it in the CSS but really it's just to split results 1-5 and 6-9. Here's my code. Screenshot attached as well. Thank you
<div class="item summary">
<h3> <?=l(479)?> </h3>
<div data-bind="foreach:$data.summary">
<div>
<span data-bind="text:$data.sequence + '.'"></span>
<span data-bind="text:$data.label + ':'"></span>
<span data-bind="text:$data.value"></span>
</div>
</div>
</div>
If the length isn't going to change you can duplicate the markup for each block and add a slice(). It's not the most elegant but it's probably the easiest.
<!-- ko if: summary && summary.length > 0 -->
<div data-bind="foreach: $data.summary.slice(0,5)">
...
<div data-bind="foreach: $data.summary.slice(5)">
...
<!-- /ko -->
If you want something a little more dynamic you can create a computed function that splits your array into multiple pieces and use a nested foreach instead:
function viewModel(){
var self = this;
this.summary = [
new Summary(1),
new Summary(2),
new Summary(3),
new Summary(4),
new Summary(5),
];
this.summaryBlocks = ko.computed(function(){
if(self.summary && self.summary.length > 0){
var size = self.summary.length / 2;
return [
self.summary.slice(0,size),
self.summary.slice(size)
];
}else{
return [];
}
});
}
function Summary(val){
this.sequence = 'sequence';
this.label = 'label';
this.value = val;
}
ko.applyBindings(new viewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div class="item summary">
<h3> <?=l(479)?> </h3>
<div data-bind="foreach: summaryBlocks">
<div style="display:inline-block; vertical-align:top;" data-bind="foreach:$data">
<div>
<span data-bind="text:$data.sequence + '.'"></span>
<span data-bind="text:$data.label + ':'"></span>
<span data-bind="text:$data.value"></span>
</div>
</div>
</div>
</div>
EDIT: Another snippet for dealing with a variable number of columns
function viewModel() {
var self = this;
this.columns = ko.observable(1);
this.summary = [new Summary(1), new Summary(2), new Summary(3), new Summary(4), new Summary(5), new Summary(6), new Summary(7), new Summary(8), new Summary(9)];
this.summaryBlocks = ko.pureComputed(function() {
var result = [];
for (var i = 0; i < self.columns(); i++) result.push([]);
if (self.summary && self.summary.length > 0) {
for (var i = 0; i < self.summary.length; i++) {
var col = i % self.columns();
result[col].push(self.summary[i]);
}
}
return result;
});
}
function Summary(val) {
this.sequence = 'sequence';
this.label = 'label';
this.value = val;
}
ko.applyBindings(new viewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
columns: <span data-bind="text: columns"></span>
<br/><input type="range" min=1 max=5 data-bind="value: columns" />
<div class="item summary">
<div data-bind="foreach: summaryBlocks">
<div style="display:inline-block; vertical-align:top;" data-bind="foreach:$data">
<div style="border: 1px dashed blue;">
<span data-bind="text:'item ' + value"></span>
</div>
</div>
</div>
</div>

ng-if condition always fails

I'm using AngularJS
<div ng-repeat="l in kites">
<a ng-click="findit(l.green.num)">color</a>
<span ng-if="c_{{l.green.num}} == 'y'>kites is </span>
</div>
In my controller I have
$scope.cnt=[];
$scope.findit = function(c){
$scope.cnt.push(c);
angular.forEach($scope.cnt, function(value, key){
$scope['c_'+value] = 'y' ;
})
}
My problem is, I'm not getting the span value even the conditions falls true..
means while l.green.num is 5 , c_5 ='y'. But it is not accepted in the if condition. Please help me.
Below is your solution:
var $scope;
var app = angular.module('miniapp', []);
function Ctrl($scope) {
$scope.kites = [{
'green':{
'num':1
}
}]
$scope.cnt = [];
$scope.findit = function(c) {
$scope.cnt.push(c);
angular.forEach($scope.cnt, function(value, key) {
$scope['c_' + value] = 'y';
})
}
};
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="miniapp" ng-controller="Ctrl">
<div ng-repeat="l in kites">
<a ng-click="findit(l.green.num)">color</a>
<span ng-show="{{'c_'+l.green.num}} == 'y'">kites is </span>
</div>
</div>
I'm not sure you can use brackets in ng-if conditions. This won't interpolate the value before evaluation.
What you could do is adding a "selected" value to your kite when clicked.
Example :
Controller
$scope.findit = function(c){
c.selected = true;
}
View
<div ng-repeat="l in kites">
<a ng-click="findit(l.green)">color</a>
<span ng-if="l.green.selected">kites is </span>
</div>

Calculate a total from autocomplete suggestion.data

I'm trying to write a small Jquery program with an autocomplete searchform. I would like the user to be able to add items from the autocomplete form to a sort of shopping list. I have difficulties finding a way to calculate and update the total price of all added products, I tried to store the prices, which are in suggestion.data and tot add it recusively to a total as in
total = total + suggestion.data, but this seems not to be the way. Could someone help me to produce and display this total? My jQuery code is as follows:
var Price = {};
var Name = {};
var Totaal = {};
$(function () {
var currencies = [
{value:'TEXT-STRING',data:'5.50)'},
{value:'TEXT-STRING2',data:'3.10)'},
];
$('#autocomplete').autocomplete({
lookup: currencies,
onSelect: function (suggestion) {
Price.fff = suggestion.data;
Name.fff = suggestion.value;
},
});
});
function addListItem() {
var write2 = Price.fff;
var write = $('#autocomplete').val();
var list = $('#itemList');
var item = $('<li><span class="list">' + write + '</span><button
class="delete">X</button></li>');
var autocomplete = $("#autocomplete");
if (write.length === 0 || write.length > 88) {
return false;
}
if (write == Name.fff) {
list.append(item);
list2.append(item2);
$(autocomplete).val('');
}
$(autocomplete).val('');
}
function deleteItem() {
$(this).parent().remove();
}
$(function () {
var add = $('#addItem');
var autocomplete = $('#autocomplete');
var list = $('#itemList');
add.on('click', addListItem);
list.on('click', '.delete', deleteItem);
autocomplete.on('keypress', function (e) {
if (e.which == 13) {
addListItem();
}
}
And my HTML looks like:
<body>
<div id="box-1"> </div>
<div id="box-2"> </div>
<div id="page">
<h1>Shop</h1>
</div>
<div id="main">
<div id="top">
<div id="form">
<div id="searchfield">
<input type="text" id="autocomplete" name="currency" class="biginput" placeholder="ADD ITEMS BELOW">
<input type="submit" id="addItem" value="+">
</div>
<div class="line"> </div>
</div>
<div id="bottom">
<div class="items">
<ul id="itemList">
</ul>
</div>
</div>
Keep added item in array with prices, so you can recalculate total at any time. Don't forget to remove it from array when removing from the list.
Don't keep data in DOM, use DOM only to display info that is in your model.