Load data from Database to DropDownList using Knockout - javascript

I'm creating editing a variable length list using knockout.
When I click Add Button, it will add a DropDownList and a TextBox to the screen. I've successfully load the data from database to DropDownList, but it always populating the data every time I clicked Add Button.
Code:
<div class="form-horizontal" data-bind="with: purchaseOrder">
<h4>Purchase Order</h4>
<hr />
<div class="form-group">
<label class="control-label col-md-2" for="PurchaseOrderDate">PO Date</label>
<div class="col-md-10">
<input class="form-control" data-bind="value: PurchaseOrderDate" placeholder="Purchase Order Date" />
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="InvoiceNo">Invoice No</label>
<div class="col-md-10">
<input class="form-control" data-bind="value: InvoiceNo" placeholder="Invoice No" />
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="Memo">Memo</label>
<div class="col-md-10">
<input class="form-control" data-bind="value: Memo" placeholder="Enter Memo" />
</div>
</div>
</div>
<h4>Details</h4>
<hr />
<table class="table">
<thead>
<tr>
<th>Item Name</th>
<th>Qty Order</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: purchaseOrderDetails">
<tr>
<td>
<select class="form-control" data-bind="options: AX_INVENTSUMs, optionsText: 'ITEMNAME', optionValue: 'ITEMID'"></select>
</td>
<td>
<input class="form-control" data-bind="value: QuantityOrder" placeholder="Enter Quantity Order">
</td>
<td>
<a class="btn btn-sm btn-danger" href='#' data-bind=' click: $parent.removeItem'>X</a>
</td>
</tr>
</tbody>
</table>
<p>
<button class="btn btn-sm btn-primary" data-bind='click: addItem'>Add Item</button>
</p>
#section Scripts {
#Scripts.Render("~/bundles/knockout")
<script>
$(function () {
var PurchaseOrder = function (purchaseOrder) {
var self = this;
self.PurchaseOrderID = ko.observable(purchaseOrder ? purchaseOrder.PurchaseOrderID : 0);
self.PurchaseOrderDate = ko.observable(purchaseOrder ? purchaseOrder.PurchaseOrderDate : '');
self.InvoiceNo = ko.observable(purchaseOrder ? purchaseOrder.InvoiceNo : '');
self.Memo = ko.observable(purchaseOrder ? purchaseOrder.Memo : '');
};
var PurchaseOrderDetail = function (purchaseOrderDetail, items) {
var self = this;
self.PurchaseOrderDetailID = ko.observable(purchaseOrderDetail ? purchaseOrderDetail.PurchaseOrderDetailID : 0);
self.PurchaseOrderID = ko.observable(purchaseOrderDetail ? purchaseOrderDetail.PurchaseOrderDetailID : 0);
self.ItemID = ko.observable(purchaseOrderDetail ? purchaseOrderDetail.ItemID : 0);
self.QuantityOrder = ko.observable(purchaseOrderDetail ? purchaseOrderDetail.QuantityOrder : 0);
self.QuantityBonus = ko.observable(purchaseOrderDetail ? purchaseOrderDetail.QuantityBonus : 0);
self.AX_INVENTSUMs = ko.observableArray(items);
};
var PurchaseOrderCollection = function () {
var self = this;
self.purchaseOrder = ko.observable(new PurchaseOrder());
self.purchaseOrderDetails = ko.observableArray([new PurchaseOrderDetail()]);
self.CashedArray = ko.observableArray([]);
$.getJSON("/AX_INVENTSUM/GetAX_INVENTSUMs", null, function (data) {
var array = [];
$.each(data, function (index, value) {
array.push(value);
});
self.CashedArray(array);
});
self.addItem = function () {
self.purchaseOrderDetails.push(new PurchaseOrderDetail(null, self.CashedArray));
};
self.removeItem = function (purchaseOrderDetail) {
self.purchaseOrderDetails.remove(purchaseOrderDetail);
};
};
ko.applyBindings(new PurchaseOrderCollection());
});
</script>
}
As you can see in the code above, how to make this occurs only once a time?

You must cache your list somewhere. I prefer to do it in something like parent view model. See bellow.
var OrderList = function(){
var self = this;
...
self.CashedArray = ko.observableArray(new Array());
$.getJSON("/AX_INVENTSUM/GetAX_INVENTSUMs", null, function (data) {
var array = [];
$.each(data, function (index, value) {
array.push(value);
});
self.CashedArray(array);
});
self.AddButtonClick = function (){
var orderDetails = new PurchaseOrderDetail(self.CashedArray());
};
};
var PurchaseOrderDetail = function (items) {
var self = this;
...
self.AX_INVENTSUMs = ko.observableArray(items);
};

Related

jQuery autocomplete not working

I am using jQuery-UI autocomplete on angular controller.
On the server side I have MVC, C# 6.0.
Autocomplete simply doesn't work, nothing shows up. I've checked with debugger how many results are returned from server - results are returned:
But nothing happens on the GUI. No drop down list showed up, nothing. No error in the console.
Here is angular controller / function:
angular.module("calendarDefinitionModule")
.controller("calendarDefinitionController", ["$scope", "$http", function ($scope, $http) {
$scope.UrlDeliveryListPaging = null;
$scope.SearchResults = null;
$scope.SearchDishSemiDishMerc = function (srt) {
if ($(event.currentTarget) === null || $(event.currentTarget).val().length < 3) {
return;
}
var objTrigger = event.currentTarget;
$http({
method: "POST",
url: $scope.UrlDeliveryListPaging,
data: {
cSEARCH_STRING: $(event.currentTarget).val(),
cSEARCH_DISH: srt === 'dish' ? '1' : null,
cSEARCH_SEDI: srt === 'semidish' ? '1' : null,
cSEARCH_MERC: srt === 'merc' ? '1' : null
}
}).then(function success(response) {
if (response.data === null) {
return;
}
$scope.SearchResults = [];
var i;
for (i = 0; i < response.data.length; ++i) {
var iKEY = srt === 'dish' || srt === 'semidish' ? response.data[i]["iDISH_KEY"] : response.data[i]["iMERC_KEY"];
var item =
{
iDISH_KEY: response.data[i]["iDISH_KEY"],
iMERC_KEY: response.data[i]["iMERC_KEY"],
iKEY: iKEY,
cDICA_NME: response.data[i]["cDICA_NME"],
cDICA_UNI: response.data[i]["cDICA_UNI"],
cSEARCH_RESULT: response.data[i]["cDICA_NME"] + " ID: " + iKEY
}
$scope.SearchResults.push(item);
}
$(objTrigger).autocomplete({
source: $scope.SearchResults,
select: function (event, ui) {
$(objTrigger).val(ui.item.cSEARCH_RESULT);
$(objTrigger).parent().parent().find("#inputDish_ID").val(ui.item.iKEY);
$(objTrigger).parent().parent().find("inputDish_UNI").val(ui.item.cDICA_UNI);
}
});
}, function failure() {
alert("Napaka pri iskanju!");
})
}
}
On the server side I've included:
ScriptBundle scriptsControllerDefinition = new ScriptBundle("~/scripts/ControllerDefinition");
scriptsControllerDefinition.Include("~/static/scripts/jquery-1.11.0.min.js");
scriptsControllerDefinition.Include("~/static/jquery.ui/js/jquery-ui-1.10.4.custom.js");
scriptsControllerDefinition.Include("~/Scripts/angular.js");
scriptsControllerDefinition.Include("~/Scripts/Angular/CalendarDefinition/calendarDefinitionModule.js");
scriptsControllerDefinition.Include("~/Scripts/Angular/CalendarDefinition/calendarDefinitionController.js");
And here is .cshtml:
<div class="form-group col-sm-12">
<label for="addDish" class="col-sm-2 control-label" style="padding-left:0;">Dodaj jed: </label>
<div class="col-sm-10">
<table id="tblDishes" style="width:100%;border-collapse:collapse;">
<tbody>
<tr id="1">
<td>
<div class="col-sm-2" style="padding-left:0;padding-right:0;">
<input id="inputDish_ID" type="text" class="form-control" placeholder="ID" readonly />
</div>
<div class="col-sm-7" style="padding-right:0;">
<input id="inputDish_NME" type="text" class="form-control" placeholder="Vnesite jed" ng-keyup="SearchDishSemiDishMerc('dish');" />
</div>
<div class="col-sm-1" style="padding-right:0;">
<input id="inputDish_UNI" type="text" class="form-control" placeholder="Enota" readonly />
</div>
<div class="col-sm-1" style="padding-right:0;">
<input id="inputDish_QUA" type="text" class="form-control bfh-number" placeholder="Količina" />
</div>
<div class="col-sm-1" style="padding-right:0;">
<span class="glyphicon glyphicon-plus add-new-dish pull-left" style="font-size:18px;color:green;cursor:pointer;padding-top:1px;"></span>
<span class='glyphicon glyphicon-trash delete-dish pull-right' style='font-size:18px;color:red;cursor:pointer;padding-top:1px;'></span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div><br />

angularjs - [$injector:modulerr] error

<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<title>Batch editable table</title>
<link rel='stylesheet prefetch' href='http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css'>
<link rel='stylesheet prefetch' href='https://cdn.rawgit.com/esvit/ng-table/v0.8.1/dist/ng-table.min.css'>
<link rel='stylesheet prefetch' href='css/nqjzro.css'>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div ng-app="myApp" class="container-fluid">
<div class="row">
<div class="col-xs-12">
<h2 class="page-header">Batch editable table</h2>
<div class="row">
<div class="col-md-6">
<div class="bs-callout bs-callout-info">
<h4>Overview</h4>
<p>Example of how to create a batch editable table.</p>
</div>
</div>
<div class="col-md-6">
<div class="bs-callout bs-callout-warning">
<h4>Notice</h4>
<p>There are several directives in use that track dirty state and validity of the table rows. Whilst they are reasonally capable they are <em>not production tested - use at your own risk!</em> More details...</p>
<div ng-show="isExplanationOpen">
<p>If you look at the declarative markup for the <code>ngTable</code> you'll see a bunch of nested <code>ngForm</code> directives, with a common ancestor <code>ngForm</code> at the level of the table element. Each nested <code>ngForm</code> propogates their <code>$dirty</code> and <code>$invalid</code> state to this top level <code>ngForm</code>. This works great as you can enable/disable the buttons for saving the table based on the status of this single top-level <code>ngForm</code>.</p>
<p>This works up till the point that the user select's a new page to display in the table. At which point the existing nested <code>ngForm</code> directives are swapped out for new instances as the new data page is loaded. These new <code>ngForm</code> directives are always pristine and valid and this status propogates setting the corrosponding state on the top-level to be pristine and valid even though rows from the previous page are dirty and possibly invalid.</p>
<p>The solution is to have a set of directives that sit parallel to the <code>ngForm</code> directives that remember the state of the rows when the corrosponding <code>ngFrom</code> directives are destroyed and recreated. When <code>ngForm</code> directives are recreated they have their status reset by the directives that have remembered this state.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6" ng-controller="demoController as demo">
<h3>ngTable directive</h3>
<div class="brn-group pull-right">
<button class="btn btn-default" ng-if="demo.isEditing" ng-click="demo.cancelChanges()">
<span class="glyphicon glyphicon-remove"></span>
</button>
<button class="btn btn-primary" ng-if="!demo.isEditing" ng-click="demo.isEditing = true">
<span class="glyphicon glyphicon-pencil"></span>
</button>
<button class="btn btn-primary" ng-if="demo.isEditing" ng-disabled="!demo.hasChanges() || demo.tableTracker.$invalid" ng-click="demo.saveChanges()">
<span class="glyphicon glyphicon-ok"></span>
</button>
<button class="btn btn-default" ng-click="demo.add()">
<span class="glyphicon glyphicon-plus"></span>
</button>
</div>
<table ng-table="demo.tableParams" class="table table-bordered table-hover table-condensed editable-table" ng-form="demo.tableForm" disable-filter="demo.isAdding" demo-tracked-table="demo.tableTracker">
<colgroup>
<col width="70%" />
<col width="12%" />
<col width="13%" />
<col width="5%" />
</colgroup>
<tr ng-repeat="row in $data" ng-form="rowForm" demo-tracked-table-row="row">
<td title="'Name'" filter="{name: 'text'}" sortable="'name'" ng-switch="demo.isEditing" ng-class="name.$dirty ? 'bg-warning' : ''" ng-form="name" demo-tracked-table-cell>
<span ng-switch-default class="editable-text">{{row.name}}</span>
<div class="controls" ng-class="name.$invalid && name.$dirty ? 'has-error' : ''" ng-switch-when="true">
<input type="text" name="name" ng-model="row.name" class="editable-input form-control input-sm" required />
</div>
</td>
<td title="'Age'" filter="{age: 'number'}" sortable="'age'" ng-switch="demo.isEditing" ng-class="age.$dirty ? 'bg-warning' : ''" ng-form="age" demo-tracked-table-cell>
<span ng-switch-default class="editable-text">{{row.age}}</span>
<div class="controls" ng-class="age.$invalid && age.$dirty ? 'has-error' : ''" ng-switch-when="true">
<input type="number" name="age" ng-model="row.age" class="editable-input form-control input-sm" required/>
</div>
</td>
<td title="'Money'" filter="{money: 'number'}" sortable="'money'" ng-switch="demo.isEditing" ng-class="money.$dirty ? 'bg-warning' : ''" ng-form="money" demo-tracked-table-cell>
<span ng-switch-default class="editable-text">{{row.money}}</span>
<div class="controls" ng-class="money.$invalid && money.$dirty ? 'has-error' : ''" ng-switch-when="true">
<input type="number" name="money" ng-model="row.money" class="editable-input form-control input-sm" required/>
</div>
</td>
<td>
<button class="btn btn-danger btn-sm" ng-click="demo.del(row)" ng-disabled="!demo.isEditing"><span class="glyphicon glyphicon-trash"></span></button>
</td>
</tr>
</table>
</div>
<div class="col-md-6" ng-controller="dynamicDemoController as demo">
<h3>ngTableDynamic directive</h3>
<div class="brn-group pull-right">
<button class="btn btn-default" ng-if="demo.isEditing" ng-click="demo.cancelChanges()">
<span class="glyphicon glyphicon-remove"></span>
</button>
<button class="btn btn-primary" ng-if="!demo.isEditing" ng-click="demo.isEditing = true">
<span class="glyphicon glyphicon-pencil"></span>
</button>
<button class="btn btn-primary" ng-if="demo.isEditing" ng-disabled="!demo.hasChanges() || demo.tableTracker.$invalid" ng-click="demo.saveChanges()">
<span class="glyphicon glyphicon-ok"></span>
</button>
<button class="btn btn-default" ng-click="demo.add()">
<span class="glyphicon glyphicon-plus"></span>
</button>
</div>
<table ng-table-dynamic="demo.tableParams with demo.cols" class="table table-bordered table-condensed table-hover editable-table" ng-form="demo.tableForm" disable-filter="demo.isAdding" demo-tracked-table="demo.tableTracker">
<colgroup>
<col width="70%" />
<col width="12%" />
<col width="13%" />
<col width="5%" />
</colgroup>
<tr ng-repeat="row in $data" ng-form="rowForm" demo-tracked-table-row="row">
<td ng-repeat="col in $columns" ng-class="rowForm[col.field].$dirty ? 'bg-warning' : ''" ng-form="{{col.field}}" demo-tracked-table-cell>
<span ng-if="col.dataType !== 'command' && !demo.isEditing" class="editable-text">{{row[col.field]}}</span>
<div ng-if="col.dataType !== 'command' && demo.isEditing" class="controls" ng-class="rowForm[col.field].$invalid && rowForm[col.field].$dirty ? 'has-error' : ''" ng-switch="col.dataType">
<input ng-switch-default type="text" name="{{col.field}}" ng-model="row[col.field]" class="editable-input form-control input-sm" required />
<input ng-switch-when="number" type="number" name="{{col.field}}" ng-model="row[col.field]" class="editable-input form-control input-sm" required />
</div>
<button ng-if="col.dataType === 'command'" class="btn btn-danger btn-sm" ng-click="demo.del(row)" ng-disabled="!demo.isEditing"><span class="glyphicon glyphicon-trash"></span></button>
</td>
</tr>
</table>
</div>
</div>
</div>
<script src='https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js'></script>
<script src='http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.4/angular.min.js'></script>
<script src='https://rawgit.com/esvit/ng-table/master/dist/ng-table.min.js'></script>
<script src="js/index.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.8/angular-route.js"></script>
</body>
</html>
The above is html code
angular.module("myApp", ["ngTable", "ngTableDemos"]);
(function() {
"use strict";
angular.module("myApp").controller("demoController", demoController);
demoController.$inject = ["NgTableParams", "ngTableSimpleList"];
function demoController(NgTableParams, simpleList) {
var self = this;
var originalData = angular.copy(simpleList);
self.tableParams = new NgTableParams({}, {
dataset: angular.copy(simpleList)
});
self.deleteCount = 0;
self.add = add;
self.cancelChanges = cancelChanges;
self.del = del;
self.hasChanges = hasChanges;
self.saveChanges = saveChanges;
//////////
function add() {
self.isEditing = true;
self.isAdding = true;
self.tableParams.settings().dataset.unshift({
name: "",
age: null,
money: null
});
// we need to ensure the user sees the new row we've just added.
// it seems a poor but reliable choice to remove sorting and move them to the first page
// where we know that our new item was added to
self.tableParams.sorting({});
self.tableParams.page(1);
self.tableParams.reload();
}
function cancelChanges() {
resetTableStatus();
var currentPage = self.tableParams.page();
self.tableParams.settings({
dataset: angular.copy(originalData)
});
// keep the user on the current page when we can
if (!self.isAdding) {
self.tableParams.page(currentPage);
}
}
function del(row) {
_.remove(self.tableParams.settings().dataset, function(item) {
return row === item;
});
self.deleteCount++;
self.tableTracker.untrack(row);
self.tableParams.reload().then(function(data) {
if (data.length === 0 && self.tableParams.total() > 0) {
self.tableParams.page(self.tableParams.page() - 1);
self.tableParams.reload();
}
});
}
function hasChanges() {
return self.tableForm.$dirty || self.deleteCount > 0
}
function resetTableStatus() {
self.isEditing = false;
self.isAdding = false;
self.deleteCount = 0;
self.tableTracker.reset();
self.tableForm.$setPristine();
}
function saveChanges() {
resetTableStatus();
var currentPage = self.tableParams.page();
originalData = angular.copy(self.tableParams.settings().dataset);
}
}
})();
(function() {
"use strict";
angular.module("myApp").controller("dynamicDemoController", dynamicDemoController);
dynamicDemoController.$inject = ["NgTableParams", "ngTableSimpleList"];
function dynamicDemoController(NgTableParams, simpleList) {
var self = this;
var originalData = angular.copy(simpleList);
self.cols = [{
field: "name",
title: "Name",
filter: {
name: "text"
},
sortable: "name",
dataType: "text"
}, {
field: "age",
title: "Age",
filter: {
age: "number"
},
sortable: "age",
dataType: "number"
}, {
field: "money",
title: "Money",
filter: {
money: "number"
},
sortable: "money",
dataType: "number"
}, {
field: "action",
title: "",
dataType: "command"
}];
self.tableParams = new NgTableParams({}, {
dataset: angular.copy(simpleList)
});
self.deleteCount = 0;
self.add = add;
self.cancelChanges = cancelChanges;
self.del = del;
self.hasChanges = hasChanges;
self.saveChanges = saveChanges;
//////////
function add() {
self.isEditing = true;
self.isAdding = true;
self.tableParams.settings().dataset.unshift({
name: "",
age: null,
money: null
});
// we need to ensure the user sees the new row we've just added.
// it seems a poor but reliable choice to remove sorting and move them to the first page
// where we know that our new item was added to
self.tableParams.sorting({});
self.tableParams.page(1);
self.tableParams.reload();
}
function cancelChanges() {
resetTableStatus();
var currentPage = self.tableParams.page();
self.tableParams.settings({
dataset: angular.copy(originalData)
});
// keep the user on the current page when we can
if (!self.isAdding) {
self.tableParams.page(currentPage);
}
}
function del(row) {
_.remove(self.tableParams.settings().dataset, function(item) {
return row === item;
});
self.deleteCount++;
self.tableTracker.untrack(row);
self.tableParams.reload().then(function(data) {
if (data.length === 0 && self.tableParams.total() > 0) {
self.tableParams.page(self.tableParams.page() - 1);
self.tableParams.reload();
}
});
}
function hasChanges() {
return self.tableForm.$dirty || self.deleteCount > 0
}
function resetTableStatus() {
self.isEditing = false;
self.isAdding = false;
self.deleteCount = 0;
self.tableTracker.reset();
self.tableForm.$setPristine();
}
function saveChanges() {
resetTableStatus();
var currentPage = self.tableParams.page();
originalData = angular.copy(self.tableParams.settings().dataset);
}
}
})();
(function() {
"use strict";
angular.module("myApp").run(configureDefaults);
configureDefaults.$inject = ["ngTableDefaults"];
function configureDefaults(ngTableDefaults) {
ngTableDefaults.params.count = 5;
ngTableDefaults.settings.counts = [];
}
})();
/**********
The following directives are necessary in order to track dirty state and validity of the rows
in the table as the user pages within the grid
------------------------
*/
(function() {
angular.module("myApp").directive("demoTrackedTable", demoTrackedTable);
demoTrackedTable.$inject = [];
function demoTrackedTable() {
return {
restrict: "A",
priority: -1,
require: "ngForm",
controller: demoTrackedTableController
};
}
demoTrackedTableController.$inject = ["$scope", "$parse", "$attrs", "$element"];
function demoTrackedTableController($scope, $parse, $attrs, $element) {
var self = this;
var tableForm = $element.controller("form");
var dirtyCellsByRow = [];
var invalidCellsByRow = [];
init();
////////
function init() {
var setter = $parse($attrs.demoTrackedTable).assign;
setter($scope, self);
$scope.$on("$destroy", function() {
setter(null);
});
self.reset = reset;
self.isCellDirty = isCellDirty;
self.setCellDirty = setCellDirty;
self.setCellInvalid = setCellInvalid;
self.untrack = untrack;
}
function getCellsForRow(row, cellsByRow) {
return _.find(cellsByRow, function(entry) {
return entry.row === row;
})
}
function isCellDirty(row, cell) {
var rowCells = getCellsForRow(row, dirtyCellsByRow);
return rowCells && rowCells.cells.indexOf(cell) !== -1;
}
function reset() {
dirtyCellsByRow = [];
invalidCellsByRow = [];
setInvalid(false);
}
function setCellDirty(row, cell, isDirty) {
setCellStatus(row, cell, isDirty, dirtyCellsByRow);
}
function setCellInvalid(row, cell, isInvalid) {
setCellStatus(row, cell, isInvalid, invalidCellsByRow);
setInvalid(invalidCellsByRow.length > 0);
}
function setCellStatus(row, cell, value, cellsByRow) {
var rowCells = getCellsForRow(row, cellsByRow);
if (!rowCells && !value) {
return;
}
if (value) {
if (!rowCells) {
rowCells = {
row: row,
cells: []
};
cellsByRow.push(rowCells);
}
if (rowCells.cells.indexOf(cell) === -1) {
rowCells.cells.push(cell);
}
} else {
_.remove(rowCells.cells, function(item) {
return cell === item;
});
if (rowCells.cells.length === 0) {
_.remove(cellsByRow, function(item) {
return rowCells === item;
});
}
}
}
function setInvalid(isInvalid) {
self.$invalid = isInvalid;
self.$valid = !isInvalid;
}
function untrack(row) {
_.remove(invalidCellsByRow, function(item) {
return item.row === row;
});
_.remove(dirtyCellsByRow, function(item) {
return item.row === row;
});
setInvalid(invalidCellsByRow.length > 0);
}
}
})();
(function() {
angular.module("myApp").directive("demoTrackedTableRow", demoTrackedTableRow);
demoTrackedTableRow.$inject = [];
function demoTrackedTableRow() {
return {
restrict: "A",
priority: -1,
require: ["^demoTrackedTable", "ngForm"],
controller: demoTrackedTableRowController
};
}
demoTrackedTableRowController.$inject = ["$attrs", "$element", "$parse", "$scope"];
function demoTrackedTableRowController($attrs, $element, $parse, $scope) {
var self = this;
var row = $parse($attrs.demoTrackedTableRow)($scope);
var rowFormCtrl = $element.controller("form");
var trackedTableCtrl = $element.controller("demoTrackedTable");
self.isCellDirty = isCellDirty;
self.setCellDirty = setCellDirty;
self.setCellInvalid = setCellInvalid;
function isCellDirty(cell) {
return trackedTableCtrl.isCellDirty(row, cell);
}
function setCellDirty(cell, isDirty) {
trackedTableCtrl.setCellDirty(row, cell, isDirty)
}
function setCellInvalid(cell, isInvalid) {
trackedTableCtrl.setCellInvalid(row, cell, isInvalid)
}
}
})();
(function() {
angular.module("myApp").directive("demoTrackedTableCell", demoTrackedTableCell);
demoTrackedTableCell.$inject = [];
function demoTrackedTableCell() {
return {
restrict: "A",
priority: -1,
scope: true,
require: ["^demoTrackedTableRow", "ngForm"],
controller: demoTrackedTableCellController
};
}
demoTrackedTableCellController.$inject = ["$attrs", "$element", "$scope"];
function demoTrackedTableCellController($attrs, $element, $scope) {
var self = this;
var cellFormCtrl = $element.controller("form");
var cellName = cellFormCtrl.$name;
var trackedTableRowCtrl = $element.controller("demoTrackedTableRow");
if (trackedTableRowCtrl.isCellDirty(cellName)) {
cellFormCtrl.$setDirty();
} else {
cellFormCtrl.$setPristine();
}
// note: we don't have to force setting validaty as angular will run validations
// when we page back to a row that contains invalid data
$scope.$watch(function() {
return cellFormCtrl.$dirty;
}, function(newValue, oldValue) {
if (newValue === oldValue) return;
trackedTableRowCtrl.setCellDirty(cellName, newValue);
});
$scope.$watch(function() {
return cellFormCtrl.$invalid;
}, function(newValue, oldValue) {
if (newValue === oldValue) return;
trackedTableRowCtrl.setCellInvalid(cellName, newValue);
});
}
})();
This is javascript file
The above code is angularjs. It displays table loading data with add row, delete, edit.
Please solve this. Am getting error [$injector:modulerr] . Please help me to solve
Edit: They created different codepen for ngTableDemos look here
To run your sample you need to load that ngTableDemos related code first then your sample.
For codepen, to understand what are the files they are using to run any sample check Pen Setting JavaScript tab carefully.
Probably you didn't load "ngTableDemos" module, so if it is needed load associate file or remove it like
angular.module("myApp", ["ngTable"]);

print function is calling before partial view

What I am trying to do is to open partial view in new window and call print function, but problem is that partial view renders after print function so I always get a blank page. I tried with $timeout function but I get the same result. For now, I have this but this is a hacky solution and I don't like it:
$scope.print = function() {
setTimeout(function() {
print()
}, 1000);
}
This is html of page that i try to open:
<div id="printWrapper" style="background-color:white;" ng-controller="accountContentController" ng-init="print()">
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<!-- HEADER -->
<tr>
<td>
<img id="imgLogo" src="#Model.TicketPayOut.Logo" />
</td>
</tr>
<!--HEADER-->
<tr>
<td>
<label id="lblTerminalId" class="left-position padding-top-3 padding-left-3 text-style">#Translator.Translate("TERMINAL")</label>
<span class="left-position padding-top-3 text-style">:</span>
<label id="lblTerminalIdValue" class="left-position padding-top-3 padding-left-3 text-style"></label>
<div style="clear:both"></div>
<label id="lblTerminalName" class="left-position padding-left-3 text-style">#Translator.Translate("BET_OFFICE")</label>
<span class="left-post text-style">:</span>
<label id="lblTerminalNameValue" class="left-position padding-left-3 text-style"></label>
<label id="lblTerminalCityAddress" class="left-position padding-left-3 text-style" style="clear:both;"></label>
<label id="lblCompanyInfo" class="center-position text-style" style="clear:both;"></label>
<label id="lblCompanyAddress" class="center-position text-style" style="clear:both;"></label>
<label id="lblCompanyId" class="center-position text-style" style="clear:both;"></label>
</td>
</tr>
<tr>
<td class="border-top border-bottom">
<div style="padding:10px 0;">
<label id="lblStornoMessage" class="center-position text-style">#Translator.Translate("PAYOUT_CONFIRMATION")</label>
</div>
</td>
</tr>
<tr>
<td class="border-bottom">
<div style="height:25px;padding:10px 3px 0 3px;">
<label id="lblPayoutTicket" class="left-position text-style">#Translator.Translate("PAYOUT_TICKET")</label>
<label id="lblPinValue" class="right-position text-style">{{payoutTime | date: dateFormat }}</label>
</div>
</td>
</tr>
<tr>
<td>
<div style="padding:5px 3px;">
<label id="lblPinTicket" class="left-position text-style">#Translator.Translate("PIN")</label>
<label id="lblPinReturnValue" class="right-position text-style">{{ticketPin}}</label>
</div>
</td>
</tr>
<tr>
<td>
<div style="padding:5px 3px;">
<label id="lblPayinReturn" class="left-position text-style">#Translator.Translate("PAYOUT_AMOUNT")</label>
<label id="lblPayinReturnValue" class="right-position text-style">{{payoutAmount}}</label>
</div>
</td>
</tr>
<tr>
<td class="border-bottom">
<div style="padding:25px 3px 5px 3px;">
<label id="lblCreatedBy" class="left-post text-style">#Translator.Translate("CREATED_BY")</label>
<label id="lblCreatedByValue" class="right-position text-style">#User.Identity.Name</label>
</div>
</td>
</tr>
</table>
</div>
This is button on page where i have print option :
<div class="mr-10">
<div class="pull-right padding-8 mt5 col-lg-2 col-md-2">
<input type="submit" value="#Translator.Translate("CANCEL")" class="btn btn-block secondary-button save-changes padding-8" ng-click="CancelPayOutTicket(ticketPin)" />
</div>
<div class="pull-right padding-8 mt5 col-lg-2 col-md-2">
<input type="submit" value="#Translator.Translate("PAYOUT")" class="btn btn-block save-changes padding-8" ng-class="{'secondary-button':TicketsPayout.BettingSlipResult.TicketHolder.PayoutEnabled==true,'disabled_button':TicketsPayout.BettingSlipResult.TicketHolder.PayoutEnabled==false}" ng-disabled="TicketsPayout.BettingSlipResult.TicketHolder.PayoutEnabled==false" ng-click="FinishTicketPayout(ticketPin);ConfirmTicketPayOut(ticketPin,'#username')"/>
</div>
</div>
Is there any way to avoid setTimeout function and just call print function in new window and populate partial view with data?
EDIT: angular controller:
$scope.CheckTicket = function (ticketPin) {
if (ticketPin != null && ticketPin != "" && ticketPin != undefined) {
var promise = accountDataProviderService.checkTicketPayout(ticketPin);
$scope.checkPromise = promise;
promise.then(
function (response) {
$scope.showTicketPayout = true;
$scope.TicketsPayout = response;
},
function (err) {
$scope.showTicketPayout = false;
$scope.ticketNotFound = true;
$timeout(function ()
{
$scope.ticketNotFound = false;
}, ticketNotFound * 1000);
});
}
}
$scope.CloseMessage = function ()
{
$scope.ticketNotFound = false;
}
$scope.FinishTicketPayout = function (ticketPin)
{
accountDataProviderService.finishTicketPayOut(ticketPin)
.then(function (response) {
$scope.finishTicketPayOut = response;
localStorage.setItem("payoutTime", $scope.finishTicketPayOut.PayoutTime);
localStorage.setItem("payoutAmount", $scope.finishTicketPayOut.PayoutAmount);
});
}
$scope.ConfirmTicketPayOut = function (ticketPin, username) {
$scope.ticketPin = ticketPin;
localStorage.setItem("pin", ticketPin);
accountDataProviderService.confirmTicketPayOut(ticketPin, username)
.then(function (response) {
$scope.confirmTicketPayOut = response;
if ($scope.confirmTicketPayOut.Result == true) {
var newWindow = window.open("/print")
}
});
localStorage.clear();
}
make the data "package" a promise inside your controller:
angular.module("printModule").controller('printController', ['$scope', '$window', '$q', function ($scope, $window, $q) {
$scope.ticketPin = localStorage.getItem("pin");
$scope.payoutTime = localStorage.getItem("payoutTime");
$scope.payoutAmount = localStorage.getItem("payoutAmount");
var defer = $q.defer();
defer.resolve($scope.ticketPin);
defer.resolve($scope.payoutTime);
defer.resolve($scope.payoutAmount);
defer.promise.then(function () {
$window.print();
})
}]);
have a nice day ;)

How to add HTML contents Dynamically on Button Click Event with AngularJS

I need to add HTML content on Button Click event using AngularJS. Is it possible??
My index.html
<div class="form-group">
<label for="category"> How Many Questions Want You Add ? </label>
<div class="col-sm-10">
<input type="text" class="form-control input-mini" id="questionNos" name="questionNos" placeholder="Nos." ng-model="myData.questionNos">
<div class="input-append">
<button class="btn-warning btn-mini" type="button" ng-click="myData.doClick()">Generate</button>
</div>
</div>
</div>
I want to add Nos. of HTML divs as per quantity added dynamically..
myApp.js
angular.module("myApp", []).controller("AddQuestionsController",
function($scope) {
$scope.myData = {};
$scope.myData.questionNos = "";
$scope.myData.doClick = function() {
//Do Something...????
};
});
It should be possible. I would data-bind your Divs to viewModel elements, and in your doClick function create the viewModels.
I would avoid directly creating Html in your viewModel.
For example:
<div class="form-group">
<label for="category"> How Many Questions Want You Add ? </label>
<div class="col-sm-10">
<input type="text" class="form-control input-mini" id="questionNos" name="questionNos" placeholder="Nos." ng-model="myData.questionNos">
<div class="input-append">
<button class="btn-warning btn-mini" type="button" ng-click="myData.doClick()">Generate</button>
</div>
<div ng-repeat="q in myData.questions">
<!-- BIND TO Q HERE -->
</div>
</div>
</div>
And in doClick:
$scope.myData.doClick = function() {
var newQuestions = getNewQuestionViewModels($scope.myData.questionNos);
for (var i = 0; i < newQuestions.length; i++) {
$scope.myData.questions.push(newQuestions[i]);
}
};
You have to store questions in collection and do repeat.
DEMO
HTML:
<div>
<input type="text" ng-model="data.qcount">
<button type="button" ng-click="data.add()">Add</button>
</div>
<div>
<div ng-repeat="q in data.questions track by $index">
<pre>{{ q | json }}</pre>
</div>
</div>
JS:
$scope.data = {
questions: [],
qcount: 0,
add: function() {
var dummy = {
'title': 'Q title',
'body': 'Q body'
},
newQ = [];
for (var i = 0; i < $scope.data.qcount; ++i) {
newQ.push(dummy);
}
$scope.data.questions = $scope.data.questions.concat(newQ);
$scope.data.qcount = 0;
}
};

Knockout collection link binding error

Here is my Knockout ViewModel
$(document).ready(
function () {
var Crime = function (CaseNumber, DateOfIncident, Description) {
this.CaseNumber = CaseNumber;
this.DateOfIncident = DateOfIncident;
this.Description = Description;
}
var crimes = function (items) {
var self = this;
//Data
self.items = ko.observableArray(items)
//operations
self.addCrime = function () {
if ($("#AddCrimeForm").valid()) {
self.crime = new Crime($("#CaseNumber").val(), $("#DateOfIncident").val(), $("#Description").val());
//var JSONObj = { CaseNumber: $("#CaseNumber").val(), DateOfIncident: $("#DateOfIncident").val(), Description: $("#Description").val() };
self.items.push(this.crime);
$("#CaseNumber").val("");
$("#DateOfIncident").val("");
$("#Description").val("");
}
}
self.removeCrime = function (item) {
self.items().remove(item);
}
}
var initialData = new Array();
ko.applyBindings(crimes(initialData), $("#CrimeList")[0])
}
);
Here is my View, in HTML:
<form id="AddCrimeForm">
<div class="panel panel-success">
<div class="panel-heading">
<div class="form-horizontal">
<div class="row">
<div class="col-lg-11">Add a crime incident to the list</div>
<div class="col-lg-1">
<button type="button" class="btn btn-success btn-xs" onclick="addCrime()"><i class="fa fa-plus"></i> Add</button>
</div>
</div>
</div>
</div>
<div class="panel-body">
<div class="form-horizontal">
<div class="row">
<div class="col-lg-6">
<input data-val="true" data-val-number="The field Id must be a number." data-val-required="The Id field is required." id="Id" name="Id" type="hidden" value="">
<div class="form-group">
<label class="control-label col-md-4" for="CaseNumber">Case Number</label>
<div class="col-md-8">
<input class="form-control text-box single-line" data-val="true" data-val-required="The Case Number field is required." id="CaseNumber" name="CaseNumber" type="text" value="">
<span class="field-validation-valid" data-valmsg-for="CaseNumber" data-valmsg-replace="true"></span>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-4" for="DateOfIncident">Date Of Incident</label>
<div class="col-md-8">
<input class="form-control text-box single-line valid" data-val="true" data-val-required="The Date of Incident field is required." id="DateOfIncident" name="DateOfIncident" type="date" value="">
<span class="field-validation-valid" data-valmsg-for="DateOfIncident" data-valmsg-replace="true"></span>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="form-group">
<label class="control-label col-md-4" for="Description">Description</label>
<div class="col-md-8">
<textarea class="form-control text-box multi-line" data-val="true" data-val-required="The Description field is required." id="Description" name="Description"></textarea>
<span class="field-validation-valid" data-valmsg-for="Description" data-valmsg-replace="true"></span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
<table class="table table-striped table-hover " id="CrimeList">
<thead>
<tr>
<th>Case Number</th>
<th>Date of Incident</th>
<th>Description</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: items">
<tr>
<td data-bind="text: $data.CaseNumber" class="col-lg-2">Column content</td>
<td data-bind="text: $data.DateOfIncident" class="col-lg-2">Column content</td>
<td data-bind="text: $data.Description" style="text-wrap: normal" class="col-lg-7">Column content</td>
#*<td></td>
<td></td>
<td></td>*#
<td style="text-align: center" class="col-lg-1">
<i class="fa fa-trash-o"></i> Remove
</td>
</tr>
</tbody>
</table>
The error I get when adding an item relates to the binding of the "Remove" link in the table, and is as follows:
Unhandled exception at line 58, column 363 in
http://localhost:49803/Scripts/KnockOut/knockout-3.0.0.js
0x800a138f - JavaScript runtime error: Unable to get property
'removeCrime' of undefined or null reference
Now, I'm not sure what the problem here is, since I am supposed to be binding to the root, since the removeCrime method resides in the root of the ViewModel?
You are setting the removeCrime function on the window object, as crimes function is being executed in the global scope, and this points to the window.
Try using new keyword when setting a viewModel.This will create new object and set it as this.
You should also attach the add method to the window if you want to call it outside of knockout.
Another error is that you are calling remove() on an JS Array not on observable Array.
Here is the working code:
$(document).ready(
function () {
var Crime = function (CaseNumber, DateOfIncident, Description) {
this.CaseNumber = CaseNumber;
this.DateOfIncident = DateOfIncident;
this.Description = Description;
}
var crimes = function (items) {
var self = this;
//Data
self.items = ko.observableArray(items)
//operations
window.addCrime = function () {
if ($("#AddCrimeForm")) {
crime = new Crime($("#CaseNumber").val(), $("#DateOfIncident").val(), $("#Description").val());
//var JSONObj = { CaseNumber: $("#CaseNumber").val(), DateOfIncident: $("#DateOfIncident").val(), Description: $("#Description").val() };
self.items.push(this.crime);
$("#CaseNumber").val("");
$("#DateOfIncident").val("");
$("#Description").val("");
}
}
self.removeCrime = function (item) {
self.items.remove(item);
}
}
var initialData = new Array();
ko.applyBindings(new crimes(initialData), $("#CrimeList")[0])
}
);
I check your code and according to me you are missing the real power of knockout. If you are using knockout than i think there is no need to access values of input fields using jquery selectors.
I have created a js fiddle, check this:
demo fiddle
And the javascript code will look something like:
function crimeRecord(data)
{
var self = this;
self.caseNumber = data.CaseNumber;
self.dateOfIncident = data.DateOfIncident;
self.description = data.Description;
}
//Main view model
function viewModel()
{
var self = this;
self.crimeRecords = ko.observableArray();
self.newCrimeRecord = ko.observable(new crimeRecord({}));
self.addRecord = function(){
self.crimeRecords.push(self.newCrimeRecord());
self.newCrimeRecord(new crimeRecord({}));
};
self.removeRecord = function(record){
self.crimeRecords.remove(record);
};
}
$(function(){
  ko.applyBindings(new viewModel());
});
Edit - 1
As you mention doubt in your comment regarding to jquery validation, there is no need to rewrite any validation logic you can use jquery validation with this viewmodel. The following is the one way to use it:
....
self.addRecord = function(){
if($("form").valid())
{
self.crimeRecords.push(self.newCrimeRecord());
self.newCrimeRecord(new crimeRecord({}));
}
else
$("form").showErrors();
};
...
Or you can use Knockout Validation.

Categories