Enable JQuery Sortable on dropdown select - javascript

I am currently using jQuery sortable to rearrange table rows in my application. I have this all working fine except I need to introduce functionality where dragging is only enabled when the user selects a team from a drop-down box on the page. The idea is that when the user first arrives onto the view, a list of team rows will be displayed. They user can select a unique team from the dropdown and filter all the rows associated with that particular team. This is when I want to be able to enable the sortable functionality. I am using the sortable library in an Angular directive, and I am filtering all table rows in the Angular controller. If someone could please point me in the right direction I would be extremely grateful. Here is my code:
myTeam.html
<div class="row">
<!-- Header Start -->
<banner-directive banner-title="Favorite Teams">
</banner-directive>
<!-- Header End -->
<div id="wrap">
<div class="container">
<div class="row">
<div class="team-order">
<div class="team-select-wrapper" style="display: inline-block">
<h2>Select team</h2>
<select class="form-control" name="teamList" ng-model="selectedteam" ng-options="team as team.name for team in teams" ng-change="onTeamSelected()">
<option value="" disabled selected>Select a Team</option>
</select>
</div>
<strong>{{teammatches.length}}</strong>Teams:
</div>
<team-order-matches matches="teammatches" teamorder="teamorder"></team-order-matches>
</div>
</div>
</div>
</div>
<div class="team-order-matches">
<div class="content">
<table class="table" id="draggable_rows">
<thead style="position: fixed; top:182px;">
<tr>
<th class="table-col-medium">
Name
</th>
<th class="table-col-medium">
Team
</th>
<th class="table-col-medium">
Amount
</th>
<th class="table-col-large">
Win
</th>
<th class="table-col-medium">
Loss
</th>
<th class="table-col-medium">
Draw
</th>
<th class="table-col-medium">
Manager
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat-start="team in teams" class="team-order-row" id="{{team._id}}">
<td class="table-col-medium" style="position: relative;">
Name
</td>
<td class="table-col-medium">
Example
</td>
<td class="table-col-medium">
Example
</td>
<td class="table-col-large">
Example
</td>
<td class="table-col-medium">
Example
</td>
<td class="table-col-medium">
Example
</td>
<td class="table-col-medium">
Example
</td>
</tr>
</tbody>
</table>
</div>
</div>
This is my controller
function TeamOrderMatchesController($scope,$location, $filter, $window, LocaleService) {
$scope.teammatches = [];
$scope.sortColumn = sortColumn;
$scope.onTeamSelected = onTeamSelected;
//filters the list to team that is selected
function onTeamSelected(){
TeamService.getMatchEvalOrder($scope.selectedteam._id).then(function(result){
$scope.runorder = result.result;
$scope.teammatches = orderByEvalOrder($scope.runorder, filterMatchesByTeam())
});
}
//Gets the unique team list for the dropdown menu
function getTeamList(){
var teams = _.map($scope.matches, function(match){
var liveVersion = _.find(match.versions, function(version){
return match.liveVersion === version.version;
});
return liveVersion.team;
});
var uniqueTeams = _.uniq(teams, function(team){
return team._id;
});
return uniqueTeams;
}
//Captures the evaluation order of the rows dragged and dropped
function orderByEvalOrder(orderedMatchIds, matches) {
var orderedMatches = [];
if(orderedMatchIds && orderedMatchIds.length > 0){
_.each(orderedMatchIds, function(orderedmatch){
var foundMatch = _.find(matches, function(m) {
return m._id == orderedmatch;
});
if(foundMatch) {
orderedMatches.push(foundMatch);
}
});
_.each(matches, function(match){
if (orderedMatchIds.indexOf(match._id) < 0) {
orderedMatches.push(match);
}
});
}
else{
orderedMatches = matches;
}
return orderedMatches;
}
//Filters the matches on the team selected
function filterMatchesByTeam() {
return _.filter($scope.matches, function(match){
var liveVersion = _.find(match.versions, function (version) {
return match.liveVersion === version.version;
});
return liveVersion.team._id === $scope.selectedteam._id;
});
}
function sortColumn(predicate, reverse) {
$scope.sortedColumn = predicate;
$scope.matches = $filter('orderBy')($scope.matches, matchPredicate, reverse);
function matchPredicate(match) {
var column;
if (shouldSortOnRoot()) {
column = match[predicate];
} else {
setVersionColumn();
}
return column;
function shouldSortOnRoot() {
return match.hasOwnProperty(predicate);
}
function setVersionColumn() {
var tempColumn = getLiveVersion(match)[predicate];
if (tempColumn.name) {
column = tempColumn.name;
} else {
column = tempColumn;
}
}
}
}
}
enter code here
exampleApp.directive('teamOrderMatches',[ '_',teamOrderMatches]);
function teamOrderMatches(_) {
return {
restrict: 'E',
scope: {
onsave: '&',
oncancel: '&',
matches: '=',
isDraggable: '&',
runorder: '='
},
link: function(scope, elem){
var table = elem.find("#draggable_rows tbody");
function updateScope() {
var ids = _.map(table.children(), function(child){
return child.id;
});
var idsWithoutEmpty = _.filter(ids, function(id) {
return id && id !== "";
});
scope.runorder = idsWithoutEmpty;
console.log(scope.teamorder);
scope.$apply();
}
table.sortable({
axis: 'y',
items: 'tr',
connectWith: 'table',
placeholder: "highlight",
tolerance: 'pointer',
scroll: true,
sort: function(event, ui) {
var currentScrollTop = $(window).scrollTop(),
topHelper = ui.position.top,
delta = topHelper - currentScrollTop;
setTimeout(function() {
$(window).scrollTop(currentScrollTop + delta);
}, 5);
},
//Helper function to keep table from collapsing when being sorted
helper: function(e, tr){
var $originals = tr.children();
var $helper = tr.clone().addClass('clone');
$helper.children().each(function(index)
{
$(this).width($originals.eq(index).width());
});
return $helper;
},
//The update function will update the table rows scope after they have been dragged to a new position
update: function(){
updateScope();
}
}).disableSelection();
},
controller: 'TeamOrderMatchesController'
};
}

Related

Get multiple value that selected from Datatable Jquery

I have some issues in getting values from datatable that i imported from excel.
i Want to pass the rows that selected (at least can be viewed in alert), here's the case.
the value that i want is like
Name : A. Mused , No HP : 087....
Name : Aida Bugg, No HP : 089....
Name : Allie Grater, No HP : 087...
but the result is just like this screenshot :
result popup alert and data
here's the code :
html
#if (Model != null)
{
<table id="tablePenerima" class="table table-striped table-bordered animate__animated animate__fadeInRight" cellpadding="0" cellspacing="0">
<thead>
<tr>
#foreach (DataColumn col in Model.Tables[0].Columns)
{
<th align="center">#col.ColumnName</th>
}
</tr>
</thead>
<tbody>
#foreach (DataRow row in Model.Tables[0].Rows)
{
<tr >
#foreach (DataColumn col in Model.Tables[0].Columns)
{
<td align="center">#row[col.ColumnName]</td>
}
</tr>
}
</tbody>
</table>
}
and the javascript :
$(document).ready(function () {
var table = $('#tablePenerima').DataTable({
dom: 'Bfrtip',
buttons: [
'selectAll',
'selectNone',
],
select: true
});
$('#tablePenerima tbody').on('click', 'tr', function () {
$(this).toggleClass('selected');
});
$('#btnBlast').click(function () {
var ids = $.map(table.rows('.selected').data(), function (item) {
return item[0]
});
var data = $('#tablePenerima').DataTable().row('.selected').ids();
console.log(ids);
alert("Name:" + ids[0] + "\nNo HP:" + ids[2]);
});
});
I hope all of you can solve my problem because my knowledge in js is still weak. Thanks :)
I have no experience with DataTable package, but i think the problem is your map function. It returns the first row of selected rows.
var ids = $.map(table.rows('.selected').data(), function (item) {
return item[0]
});
Instead of
return item[0]
You should return all selected rows;
return item
In $('#btnBlast').click event

How to get SUM of the table field? - Angularjs & Sqlite

I'm trying to get the sum of my table row (amount) with Angularjs which is connected to my sqlite database
I have managed to build CRUD operations perfectly but now I'm stuck on getting the sum of my amount field
Here's part of my html code:
<table id="tableSales" ng-init="listSales()">
<thead class="bz-tablecell">
<tr>
<th id="table-checkbox"><input type="checkbox" onclick="toggle(this);" id="chk-all"></th>
<th><b>Name</b></th>
<th><b>Amount</b></th>
<th><b>Quantity</b></th>
<th><b>Customer</b></th>
<th><b>Date</b></th>
<th class="export-ignore"><b>Status</b></th>
<th class="export-ignore"><b>Actions</b></th>
</tr>
</thead>
<tbody>
<tr class="bz-tablecell" dir-paginate="sale in sales|filter:search|itemsPerPage:20">
<td id="table-checkbox"><input type="checkbox"></td>
<td style="font-weight: 600">{{sale.name}}</td>
<td>{{sale.amount | currency: "TZS "}}</td>
<td>{{sale.quantity}}</td>
<td>{{sale.customer}}</td>
<td>{{sale.date}}</td>
<td class="export-ignore"><span class="approved" style="border-radius: 0 !important;">{{sale.status}}</span></td>
<td class="export-ignore"><a ng-click="delete(sale)">Manage</a></td>
</tr>
<tr ng-if="sales.length <= 0">
<td colspan="8" rowspan="4" class="center empty-state">
<b class="top">There are no sales yet!</b>
<br>Start by adding a new one.
</td>
</tr>
</tbody>
</table>
And here's is my angularjs code which do CRUD operations:
"USE STRICT";
app.controller("salesController", function ($scope, $location, dbService) {
$scope.sub = {
'title': 'Sales Orders'
}
$scope.listSales = function () {
//FETCH
dbService.runAsync("SELECT * FROM sales WHERE active = 1", function (data) {
$scope.sales = data;
});
}
$scope.save = function () {
if ($scope.sale.id) {
//EDIT
var id = $scope.sale.id;
delete $scope.sale.id;
delete $scope.sale.$$hashKey;
dbService.update('sales', $scope.sale, {
id: id
});
} else {
//SAVE
dbService.insert('sales', $scope.sale);
}
$scope.sale = {};
$scope.listSales();
}
$scope.delete = function (data) {
//DELETE
if (confirm("Are you sure you want to delete this sale?")) {
dbService.update('sales', {
active: 0
}, {
id: data.id
});
$scope.listSales();
}
}
});
What I need to do is get all sum of amount field, please help. Thank you
To compute a sum:
$scope.listSales = function () {
//FETCH
dbService.runAsync("SELECT * FROM sales WHERE active = 1", function (data) {
$scope.sales = data;
//COMPUTE Sum
$scope.sum = data.reduce( ( (_,sum) => sum + _.amount) , 0);
});
}
For more information, see
MDN JavaScript Reference - array.reduce

Knockout.js Mapping and adding large dataset to ko.observableArray

There are many examples of adding large datasets to a ko.observableArray using the underlying array such as this:
ko.observableArray.fn.pushAll = function(valuesToPush) {
var underlyingArray = this();
this.valueWillMutate();
ko.utils.arrayPushAll(underlyingArray, valuesToPush);
this.valueHasMutated();
return this; //optional
};
The problem with doing it this way is I lose my observables. When I use chrome and pause in debugger, I get the values in my array rather than the function c() which is the observable wrap. I have to also observe many of these variables.
I found what does work is the following:
var model = #Html.Raw(Json.Encode(Model));
vm.POs = ko.mapping.fromJS(model.POs);
The problem is that this is slow. How do I use the underlying array to add but then add the observable wrap to each variable without performance issues?
Here is some more code:
var vm = {
POs: ko.observableArray([]),
headersWithAccounting: ko.observableArray([
{header_name: "DATE CREATED", property: "DATE_CREATED", state: ko.observable('')},
{header_name: "DATE ISSUED", property: "DATE_ISSUED", state: ko.observable('')},
{header_name: "USER CREATED", property: "NAME_USER", state: ko.observable('')},
{header_name: "PO NUMBER", property: "NO_PO", state: ko.observable('')},
{header_name: "ORDER STATUS", property: "NAME_STATUS", state: ko.observable('')},
{header_name: "VENDOR", property: "NAME_VENDOR", state: ko.observable('')},
{header_name: "TOTAL COST", property: "COST_TOTAL", state: ko.observable('')},
{header_name: "CTU", property: "ID_CTU", state: ko.observable('')},
{header_name: "ACCOUNTING CODE", property: "ACCOUNTING_CODE_NAME", state: ko.observable('')},
{header_name: "CLOSE ORDER", property: "ACCOUNTING", state: ko.observable('')}
])
};
function PO() {
var self = this;
self.ID_ORDER = ko.observable();
self.DATE_CREATED = ko.observable();
self.DATE_ISSUED = ko.observable();
self.NAME_STATUS = ko.observable();
self.NAME_VENDOR = ko.observable();
self.NAME_USER = ko.observable();
self.COST_TOTAL = ko.observable();
self.ACCOUNTING_CODE_NAME = ko.observable();
self.ACCOUNTING_CODE_ID = ko.observable();
self.NO_PO = ko.observable();
self.SHOWDETAILS = ko.observable(0);
self.ID_TYPE = ko.observable(0);
self.DESCRIPTION = ko.observable('');
self.FILES = ko.observableArray();
self.POParts = ko.observableArray();
self.ACCOUNTING = ko.observable(0);
self.ID_CTU = ko.observable(0);
self.ACCOUNTING.subscribe(function(val) {
if (vm.avoidCloseOrder() == 0) {
$.ajax({
type: "POST",
url: '#Url.Action("AccountingCloseOrder", "Report")',
dataType: 'JSON',
data: {
orderId: self.ID_ORDER()
},
success: function(msg) {
if (msg != 'Good') {
window.location.href = msg;
}
},
error: function (err) {
alert("Error closing order, please try again");
}
});
}
});
self.ACCOUNTING_CODE_ID.subscribe(function(val) {
if (vm.avoidCloseOrder() == 0) {
$.ajax({
type: "POST",
url: '#Url.Action("AccountingCodeChange", "Report")',
dataType: 'JSON',
data: {
orderId: self.ID_ORDER(),
accountingCodeId: self.ACCOUNTING_CODE_ID()
},
success: function(msg) {
},
error: function (err) {
alert("Error closing order, please try again");
}
});
}
});
}
function POPart() {
var self = this;
self.CATEGORY = ko.observable();
self.SUBCATEGORY = ko.observable();
self.DESCRIPTION = ko.observable();
self.PARTNO = ko.observable();
self.QTY_ORDERED = ko.observable();
self.QTY_RECEIVED = ko.observable();
self.COST = ko.observable();
}
function FILE() {
var self = this;
self.LOCATION = ko.observable();
}
Now the issue is in the razor code with the knockout bindings:
<div class="row">
<div class="col-md-12">
<div data-bind="foreach:POs">
<table class="table-responsive">
<thead data-bind="if: $index() == 0 || ($index() > 0 && vm.POs()[$index()-1].SHOWDETAILS() == 1)">
<tr data-bind="foreach:vm.headersWithAccounting">
<th>
<span data-bind="click:$root.sortPOs.bind(property), text:header_name" style="cursor:pointer"></span><i data-bind="css: state"></i>
</th>
</tr>
</thead>
<tbody class="clickabletbody">
<tr>
<td data-bind="click:$parent.showDetailsFor">
<div data-bind="text:DATE_CREATED"></div>
</td>
<td data-bind="click:$parent.showDetailsFor">
<div data-bind="text:DATE_ISSUED"></div>
</td>
<td data-bind="click:$parent.showDetailsFor">
<div data-bind="text:NAME_USER"></div>
</td>
<td data-bind="click:$parent.showDetailsFor">
<div data-bind="text:NO_PO"></div>
</td>
<td data-bind="click:$parent.showDetailsFor">
<div data-bind="text:NAME_STATUS"></div>
</td>
<td data-bind="click:$parent.showDetailsFor">
<div data-bind="text:NAME_VENDOR"></div>
</td>
<td data-bind="click:$parent.showDetailsFor">
<div data-bind="text:COST_TOTAL"></div>
</td>
<td data-bind="click:$parent.showDetailsFor">
<div data-bind="text:ID_CTU"></div>
</td>
<td>
#Html.DropDownList("ddlVendor", new SelectList(Model.ACCOUNTING_CODE_SELECTLIST, "Value", "Text"), "--Select Accounting Code--", new { #class = "form-control", data_bind = "value:ACCOUNTING_CODE_ID" })
</td>
<td>
<input type="checkbox" style="height:30px; width: 30px;" data-bind="checked:ACCOUNTING, enable:(NAME_STATUS() == 'ACCOUNTING' || NAME_STATUS() == 'CLOSED')" /> //PROBLEM RIGHT HERE!!!!
</td>
</tr>
</tbody>
</table>
<table data-bind="if:SHOWDETAILS, fadeVisible:SHOWDETAILS" style="background-color:antiquewhite" class="table-responsive">
<!-- ko if:(ID_TYPE() == 2 || ID_TYPE() == 3) -->
<thead>
<tr>
<th>
DESCRIPTION
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div data-bind="text:DESCRIPTION"></div>
</td>
</tr>
</tbody>
<!-- /ko -->
<!-- ko if:(ID_TYPE() == 1) -->
<thead>
<tr>
<th>
CATEGORY
</th>
<th>
SUBCATEGORY
</th>
<th>
DESCRIPTION
</th>
<th>
PART NO
</th>
<th>
QTY ORDERED
</th>
<th>
QTY RECEIVED
</th>
<th>
COST
</th>
</tr>
</thead>
<tbody data-bind="foreach:POParts">
<tr>
<td>
<div data-bind="text:CATEGORY"></div>
</td>
<td>
<div data-bind="text:SUBCATEGORY"></div>
</td>
<td>
<div data-bind="text:DESCRIPTION"></div>
</td>
<td>
<div data-bind="text:PARTNO"></div>
</td>
<td>
<div data-bind="text:QTY_ORDERED"></div>
</td>
<td>
<div data-bind="text:QTY_RECEIVED"></div>
</td>
<td>
<div data-bind="text:COST"></div>
</td>
</tr>
</tbody>
<!-- /ko -->
</table>
<table data-bind="if:SHOWDETAILS, fadeVisible:SHOWDETAILS" style="background-color:antiquewhite" class="table-responsive">
<thead>
<tr>
<th>
Files
</th>
</tr>
</thead>
<tbody data-bind="foreach:FILES">
<tr>
<td>
<a data-bind="attr: {href: LOCATION, target: '_blank'}" class="btn btn-primary btn-md">Download File</a>
</td>
</tr>
</tbody>
</table>
<div data-bind="if:SHOWDETAILS"><hr /></div>
</div>
<!-- /ko -->
</div>
</div>
The problem is with the checkbox, chrome console says error:
knockout-3.4.0.js:72 Uncaught TypeError: Unable to process binding "enable: function (){return (NAME_STATUS() =='ACCOUNTING'|| NAME_STATUS() =='CLOSED') }"
Message: NAME_STATUS is not a function
This is because in the value it is no longer a function with knockout bindings, it is simply a value, therefore it is not a function and this error is correct. I am losing this because using the underlying array pushes only the javascript values and is not mapping the observable function.
It is taking roughly 10 seconds for 200 entries to map currently using observables, which is pretty ridiculous if you ask me. What will happen when I have 1000+. Even if I only load 50 of them starting out and use ajax to gather the rest behind the scenes, every time I get more data, it will lag the page for a few seconds until it loads them all. Not sure how to go about fixing this.
Edit:
I just had an AHA moment and fixed the losing binding problem. It is taking roughly 4 seconds now for 232 entries. Would still like to get it faster but heres what I changed.
function PO(data) {
var self = this;
self.ID_ORDER = ko.observable(data.ID_ORDER);
self.DATE_CREATED = ko.observable(data.DATE_CREATED);
self.DATE_ISSUED = ko.observable(data.DATE_ISSUED);
self.NAME_STATUS = ko.observable(data.NAME_STATUS);
self.NAME_VENDOR = ko.observable(data.NAME_VENDOR);
self.NAME_USER = ko.observable(data.NAME_USER);
self.COST_TOTAL = ko.observable(data.COST_TOTAL);
self.ACCOUNTING_CODE_NAME = ko.observable(data.ACCOUNTING_CODE_NAME);
self.ACCOUNTING_CODE_ID = ko.observable(data.ACCOUNTING_CODE_ID);
self.NO_PO = ko.observable(data.NO_PO);
self.SHOWDETAILS = ko.observable(0);
self.ID_TYPE = ko.observable(data.ID_TYPE);
self.DESCRIPTION = ko.observable(data.DESCRIPTION);
self.FILES = ko.observableArray();
if (data.FILES != null) {
for (var i = 0; i < data.FILES.length; i++) {
self.FILES.push(new FILE(data.FILES[i]));
}
}
self.POParts = ko.observableArray();
if (data.POParts != null) {
for (var i = 0; i < data.POParts.length; i++) {
self.POParts.push(new POPart(data.POParts[i]));
}
}
self.ACCOUNTING = ko.observable(data.ACCOUNTING);
self.ID_CTU = ko.observable(data.ID_CTU);
self.ACCOUNTING.subscribe(function(val) {
if (vm.avoidCloseOrder() == 0) {
$.ajax({
type: "POST",
url: '#Url.Action("AccountingCloseOrder", "Report")',
dataType: 'JSON',
data: {
orderId: self.ID_ORDER()
},
success: function(msg) {
if (msg != 'Good') {
window.location.href = msg;
}
},
error: function (err) {
alert("Error closing order, please try again");
}
});
}
});
self.ACCOUNTING_CODE_ID.subscribe(function(val) {
if (vm.avoidCloseOrder() == 0) {
$.ajax({
type: "POST",
url: '#Url.Action("AccountingCodeChange", "Report")',
dataType: 'JSON',
data: {
orderId: self.ID_ORDER(),
accountingCodeId: self.ACCOUNTING_CODE_ID()
},
success: function(msg) {
},
error: function (err) {
alert("Error closing order, please try again");
}
});
}
});
}
function POPart(data) {
var self = this;
self.CATEGORY = ko.observable(data.CATEGORY);
self.SUBCATEGORY = ko.observable(data.SUBCATEGORY);
self.DESCRIPTION = ko.observable(data.DESCRIPTION);
self.PARTNO = ko.observable(data.PARTNO);
self.QTY_ORDERED = ko.observable(data.QTY_ORDERED);
self.QTY_RECEIVED = ko.observable(data.QTY_RECEIVED);
self.COST = ko.observable(data.COST);
}
function FILE(data) {
var self = this;
self.LOCATION = ko.observable(data.LOCATION);
}
And the push function:
ko.observableArray.fn.pushAll = function(valuesToPush)
{
var underlyingArray = this();
this.valueWillMutate();
ko.utils.arrayForEach(valuesToPush, function(item) {
underlyingArray.push(new PO(item));
});
this.valueHasMutated();
return this;
}
Any ideas to make this faster than 4 seconds?
I didn't really get what you mean by "I loose my bindings". It's maybe a debugger artefact (which shows you the value of the observable).
I could also be a "this" issue.
I get this snippet which is working (and you can use the click binding while array is populated)
var elementVM = (function () {
function elementVM(message) {
this.myText = ko.observable(message);
}
elementVM.prototype.changeText = function () {
this.myText(this.myText() + " changed");
};
return elementVM;
}());
var myVM = (function() {
var getText = function(count) {
return "My Text " + (count);
};
var myObservableArray = ko.observableArray([new elementVM(getText(0))]);
return function() {
this.myArray = myObservableArray;
myVM.prototype.populate = function() {
myObservableArray.valueWillMutate();
for(var i = 1; i <= 1000; ++i)
{
myObservableArray().push(new elementVM("My Text " + i));
}
myObservableArray.valueHasMutated();
};
};
}());
var vm = new myVM();
ko.applyBindings(vm);
setTimeout(function() {
var start = new Date();
vm.populate();
var stop = new Date();
document.getElementById("pushAll").innerHTML = "pushallTiming: " + (stop - start);
}, 1000);
li {
list-style: none;
border: 1px solid black;
width: auto;
text-align: center;
}
#pushAll {
background-color: red;
width: auto;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div id="pushAll"></div>
<ul data-bind="template: { name: 'my-template', foreach: myArray }"></ul>
<script type="text/html" id="my-template">
<li data-bind="text: myText, click: changeText"></li>
</script>
The actual copying to the array takes less than 1 sec. It is the valueHasMutated() function which is taking a few seconds ands thats just part of KO. I'm glad its not taking long to copy the data into the array. I will try to paginate only 50 entries which should help the DOM load faster. Thanks for everybody who responded.

filtering data by API calls

I have a table on my page and custom filters for this table, so by default I'm using API call that to load data.
$('#table').bootstrapTable('refreshOptions', {
url: 'http://address:8080/events-api1/rest/Events/'
});
On the left side I have filters. This filters I'm getting thru http get method
$http({
method: "GET",
url: "http://address:8080/events-api1/rest/EventTypeCategories"
}).then(function success(response) {
$scope.categories = response.data;
}, function error(response) {
$scope.categories = response.statusText;
});
and rendering filters thru scope function
$scope.selectCat = function () {
angular.forEach($scope.categories, function (category) {
if (category.selected) {
$scope.selectedAllCat = false;
if (category.name == "Study") {
$scope.checked = true;
$('#table').bootstrapTable('refreshOptions', {
url: 'http://address:8080/events-api1/rest/Events?category=1'
});
}
else if (category.name == "Corporate") {
$scope.checked = true;
$('#table').bootstrapTable('refreshOptions', {
url: 'http://address:8080/events-api1/rest/Events?category=2'
});
}
else if (category.name == "Safety") {
$scope.checked = true;
$('#table').bootstrapTable('refreshOptions', {
url: 'http://address:8080/events-api1/rest/Events?category=3'
});
}
else if (category.name == "Partners") {
$scope.checked = true;
$('#table').bootstrapTable('refreshOptions', {
url: 'http://address:8080/events-api1/rest/Events?category=4'
});
}
else if (category.name == "Standards") {
$scope.checked = true;
$('#table').bootstrapTable('refreshOptions', {
url: 'http://address:8080/events-api1/rest/Events?category=5'
});
}
else if (category.name == "Technology") {
$scope.checked = true;
$('#table').bootstrapTable('refreshOptions', {
url: 'http://address:8080/events-api1/rest/Events?category=6'
});
}
}
});
};
html
<div class="panel-body">
<table class="table">
<tr>
<td class="col-md-1"> <input type="checkbox" ng-model="selectedAllCat" ng-click="selectAllCat()"> </td>
<td class="col-md-9">All</td>
<td class="col-md-2">
{{ categories.length }}
</td>
</tr>
<tr ng-repeat="category in categories | orderBy : 'id' ">
<td class="col-md-1"> <input type="checkbox" ng-model="category.selected" ng-click="selectCat()"> </td>
<td class="col-md-9">{{ category.name }}</td>
<td class="col-md-2">
{{ category.selected }}
</td>
</tr>
</table>
</div>
<table id="table"
data-flat="true"
data-toggle="table"
data-toolbar="#toolbar"
data-search="true"
data-show-toggle="false"
data-show-columns="true"
data-show-export="true"
data-filter-control="true"
data-events="operateEvents"
data-formatter="operateFormatter"
data-response-handler="responseHandler"
class="table-striped">
</table>
My question is what do I have to do for multiple category selections?
EDIT: With more explanation.
Your goal here would be to compose the query string to be able to filter upon multiple categories.
When you want category 1, you do a request like:
http://address:8080/events-api/rest/Events?category=1
Now, you want to filter upon category 1 and 6 with a single request, so your request should be like this:
http://address:8080/events-api/rest/Events?category=1&category=6
So, in your code you should:
1 Change the markup from:
<td class="col-md-1"> <input type="checkbox" ng-model="category.selected" ng-click="selectCat()"> </td>
to:
<td class="col-md-1"> <input type="checkbox" ng-click="updateFilter(category.id)"> </td>
2 The following function will help us to keep track of currently marked filters:
$scope.selectedFilters = [];
$scope.updateFilter = function(categoryId) {
if ($scope.selectedFilters.indexOf(categoryId) > -1) {
$scope.selectedFilters.push(categoryId);
} else {
$scope.selectedFilters.splice($scope.selectedFilters.indexOf(categoryId), 1);
}
//Optional, to reload on change.
$scope.requestEvents();
}
3: The following function to request data, based on selected filters, will work also without filters at all.
$scope.requestEvents() {
var url = 'http://address:8080/events-api/rest/Events';
if ($scope.selectedFilters.length > -1) {
var queryString = '?category=';
queryString += $scope.selectedFilters.join('&category=');
url += queryString;
}
$('#table').bootstrapTable('refreshOptions', {
'url': url
});
}
-- Old version --
Not sure if this will be clear from the first time, but it's due to lack of details from your side. So, keeping the code style as you already have it, you can write something like this.
$scope.filterByCategory = function(categories) {
//Assuming you have in categories, an array of numbers, (or
//strings, anyway they should match categories from your backend)
categories = categories.join('&category=');
$('#table').bootstrapTable('refreshOptions', {
url: 'http://address:8080/events-api/rest/Events?category=6' + categories
}
Note, depending on your backend, query string maybe should be joined by ('&category[]='), instead of ('&category=')

KnockoutJS - extending the shopping cart example

I'm currently trying to extend the KnockoutJS shopping cart example to preload existing rows from a JSON collection.
Say, I have an object like this:
var existingRows = [{
"Category":Classic Cars,
"Product":2002 Chevy Corvette,
"Quantity":1,
}, {
"Category":Ships,
"Product":Pont Yacht,
"Quantity":2,
}];
I am trying to modify the example so that on load it populates the grid with two rows, with the comboboxes pre-set to the items in the JSON object.
I can't seem to get this object playing nicely with JSFiddle, but I've got as far as modifying the Cart and CartLine functions, and ApplyBindings call as follows:
var CartLine = function(category, product) {
var self = this;
self.category = ko.observable(category);
self.product = ko.observable(product);
// other code
}
var Cart = function(data) {
var self = this;
self.lines = ko.observableArray(ko.utils.arrayMap(data, function(row) { return new CartLine(row.Category, row.Product);}))
// other code
}
ko.applyBindings(new Cart(existingRows));
This correctly inserts two rows on load, but does not set the drop down lists. Any help would be much appreciated :)
The problem is that the values of the category and product observables in the CartLine object are not simple strings. They are actual objects, e.g. category refers to a specific category from the sample data that's provided in that example, same with product.
But you're just setting them to strings.
(Another problem is that your JS object existingRows is not valid javascript because of quotes missing around the string)
To get that example working with your existingRows object you could extract the relevant category and product from the sample data:
var Cart = function(data) {
// Stores an array of lines, and from these, can work out the grandTotal
var self = this;
self.lines = ko.observableArray(ko.utils.arrayMap(data, function(row) {
var rowCategory = ko.utils.arrayFirst(sampleProductCategories, function(category) {
return category.name == row.Category;
});
var rowProduct = ko.utils.arrayFirst(rowCategory.products, function(product) {
return product.name == row.Product;
});
return new CartLine(rowCategory, rowProduct, row.Quantity);
}));
// other code
}
Updated fiddle: http://jsfiddle.net/antishok/adNuR/664/
<h1> Online shopping</h1>
<button id="btnAdd" data-bind='click: addLine'>Add product</button><br /><br />
<table width='100%'>
<thead>
<tr>
<th width='25%'>Product</th>
<th class='price' width='15%'>Price</th>
<th class='quantity' width='10%'>Quantity</th>
<th class='price' width='15%'>Subtotal (in rupees)</th>
<th width='10%'> </th>
</tr>
</thead>
<tbody data-bind='foreach: items'>
<tr>
<td>
<select data-bind='options: products, optionsText: "name", optionsCaption: "Select...", value: product'> </select>
</td>
<td class='price' data-bind='with: product'>
<span data-bind='text: (price)'> </span>
</td>
<td class='quantity'>
<input data-bind='visible:product, value: quantity, valueUpdate: "afterkeydown"' />
</td>
<td class='price'>
<span data-bind='visible: product, text: subtotal()' > </span>
</td>
<td>
<a href='#' data-bind='click: $parent.removeLine'>Remove</a>
</td>
</tr>
</tbody>
</table>
<h2>
Total value: <span data-bind='text: grandTotal()'></span> rupees
</h2>
$(document).ready(function () {
$("#btnAdd").button();
ko.applyBindings(new OnlineShopping());
});
function formatCurrency(value) {
return "$" + value.toFixed(2);
}
var Item = function () {
var self = this;
self.product = ko.observable();
self.quantity = ko.observable(1);
self.subtotal = ko.computed(function () {
var result = self.product() ? self.product().price * parseInt("0"+self.quantity(), 10) : 0;
return result;
});
};
var OnlineShopping = function () {
var self = this;
// List of items
self.items = ko.observableArray([new Item()]);
// Compute total prize.
self.grandTotal = ko.computed(function () {
var total = 0;
$.each(self.items(), function () { total += this.subtotal() })
return total;
});
// Add item
self.addLine = function () {
self.items.push(new Item())
};
// Remove item
self.removeLine = function () {
self.items.remove(this)
};
};
// Item collection
var products = [{ name: "IPhone", price: "45000" }, { name: "Galaxy Y", price: "7448" }, { name: "IPad", price: "25000" }, { name: "Laptop", price: "35000" }, { name: "Calci", price: "750"}];

Categories