Retaining changed data on table pagination - AngularJS - angularjs

I have a requirement to submit changes made in my angularjs table. This table is populated asynchronously and so the pagination is dynamic.
Whenever I make a change in a page(eg: page 1) and move on to any other page(eg: page 2), the data changed in the page 1 is getting reset on accessing the again. The changed data is not maintained as such.
Worked on to see that, there could be few ways to avoid this.
Restricting the use of st-safe-src in table definition. (But this
option was possible only to synchronous table loading. The table is
not getting populated if I remove the safe source)
Use a variable to store/retrieve state of dynamic form controls like
this example, which had an ajax call and populated the entire input
tags based on ajax validations, which too didn't work since the
default value of my select option is be based on the DB input.
Is there a possible way to do this in angularjs?
My table:
<table id="recordTable" st-table="display_record_returns" st-safe-src="recordReturns" ng-show="recordReturns"
class="table table-bordered table-striped shadow p-3 mb-5 bg-white rounded" ng-controller="BotRulesController">
<thead class="thead-dark">
<tr>
<th style="white-space: nowrap">CASE NO</th>
<th st-sort="code">MATCH CODE</th>
<th st-sort="decision">RULE</th>
<th st-sort="email">EMAIL</th>
</tr>
</thead>
<tbody>
<tr id="row.code" valign="middle" st-select-row="row"
st-select-mode="multiple"
ng-repeat="row in display_record_returns track by row.code"
ng-attr-id="{{::row.code}}">
<td>{{$index + 1}}</td>
<td align="left" ng-bind="row.code"></td>
<td>
<select id="ruleChangeSelect_{{row.code}}" ng-change="ruleChanged(row.code, row.decision, selectionModel[row.code])" class="custom-select"
style="margin-left: 0px"
ng-model="selectionModel[row.code]"
ng-options="choice.name for choice in possibleOptions track by choice.id">
<option value="" hidden="hidden" readonly="" ng-hide="true"></option>
</select>
</td>
<td ng-bind="row.email"></td>
</tr>
</tbody>
<tfoot>
<tr style="font-size:0.8rem !important;">
<td colspan="22" class="text-center">
<div st-pagination="" st-items-by-page="itemsByPage" st-displayed-pages="5"></div>
</td>
</tr>
</tfoot>
</table>
My js:
$scope.getRules = function () {
$http({
'url': '/getRules',
'method': 'POST',
'headers': {
'Content-Type': 'application/json'
}
}).then(function (response) {
$scope.recordReturns = response.data;
$scope.ruleOptions = [{
decision: "A"
}, {
decision: "B"
}, {
decision: "C"
}];
$scope.possibleOptions = getUniqueValues($scope.ruleOptions, 'decision')
.map(function (id) {
return {
id: id,
name: id
}
});
$scope.selectionModel = {};
angular.forEach($scope.recordReturns, function (input) {
$scope.selectionModel[input.code] = $scope.possibleOptions.filter(function (opt) {
return opt.id === input.decision;
})[0];
});
function getUniqueValues(array, prop) {
return [...new Set(array.map(item => item[prop]))];
}
$window.scrollTo(0, 0);
})
};

Related

Using AngularJS, how can I match items from two separate ng-repeats?

Using AngularJS, I am creating a table that is pulling data with two web requests.
Each web request has it's own ng-repeat in the HTML, ng-repeat="user in users" and ng-repeat="app in apps". Right now all existing apps are showing in every repeat of user. What I'd like to do is some kind of match, lookup, or filter and only show apps that the user is associated with. So, when user.Title == app.Title.
Here is the HTML:
<div ng-app="myApp">
<div ng-controller="MainCtrl">
<div class="ProfileSheet" ng-repeat="user in users">
<h3 class="heading">User Profile</h3>
<table id="Profile">
<tr>
<th>User</th>
<td>{{user.Title}}</td>
</tr>
<tr>
<th>First Name</th>
<td>{{user.FirstName}}</td>
</tr>
<tr>
<th>Last Name</th>
<td>{{user.LastName}}</td>
</tr>
<tr>
<th>Job Title</th>
<td>{{user.JobTitle}}</td>
</tr>
<tr>
<th>Emp ID</th>
<td>{{user.EmployeeID}}</td>
</tr>
<tr>
<th>Officer Code</th>
<td>{{user.OfficerCode}}</td>
</tr>
<tr>
<th>Email</th>
<td>{{user.Email}}</td>
</tr>
<tr>
<th>Telephone</th>
<td>{{user.WorkPhone}}</td>
</tr>
<tr>
<th>Fax Number</th>
<td>{{user.WorkFax}}</td>
</tr>
<tr>
<th>Location Description</th>
<td>{{user.LocationDescription}}</td>
</tr>
<tr>
<th>Mailstop / Banking Center #</th>
<td>{{user.Mailstop}}</td>
</tr>
</table>
<br>
<h3 class="heading">User Applications</h3>
<div style="border:3px solid #707070; padding-right:12px;">
<h4 style="padding-left:5px;">User Applications</h4>
<table id="Apps">
<tr id="AppsHeading">
<th>Application</th>
<th>User ID</th>
<th>Initial Password</th>
<th>Options / Comment</th>
<th>Setup Status</th>
</tr>
<tr ng-repeat="app in apps">
<td>{{app.Application.Title}}</td>
<td>{{app.Title}}</td>
<td>{{app.InitialPassword}}</td>
<td>{{app.OptionsComments}}</td>
<td style="border-right:3px solid #707070;">{{app.SetupStatus}}</td>
</tr>
</table>
</div>
</div>
</div>
The JS:
var app = angular.module('myApp', ['ngSanitize']);
var basePath = "https://portal.oldnational.com/corporate/projecthub/anchormn/associates"
app.controller('MainCtrl', function($scope, $http, $q){
var supportList;
$(document).ready(function() {
$scope.getAdminList();
$scope.getAppsList();
});
// $scope.selectedIdx = -1;
// $scope.showResults = false
$scope.prepContext = function(url,listname,query){
var path = url + "/_api/web/lists/getbytitle('" + listname + "')/items" + query;
console.log(path);
return path;
}
$scope.getAdminList = function() {
supportList = $http({
method: 'GET',
url: this.prepContext(siteOrigin+"/corporate/projecthub/anchormn/associates","User Administration","?$orderBy=LastName"),
headers: {
"Accept": "application/json; odata=verbose"
}
}).then(function(data) {
//$("#articleSection").fadeIn(2000);
console.log("adminlist", data.data.d.results);
$scope.users = data.data.d.results;
});
};
$scope.getAppsList = function() {
supportList = $http({
method: 'GET',
// url: this.prepContext(siteOrigin+"/corporate/projecthub/anchormn/associates","User Applications","?$select=Title,InitialPassword,OptionsComments,SetupStatus,Application/Title&$orderBy=Application&$expand=Application"),
url: this.prepContext(siteOrigin+"/corporate/projecthub/anchormn/associates","User Applications","?$select=Title,InitialPassword,OptionsComments,SetupStatus,Application/Title,ParentUserLink/ID&$orderBy=Application&$expand=Application,ParentUserLink"),
headers: {
"Accept": "application/json; odata=verbose"
}
}).then(function(data) {
//$("#articleSection").fadeIn(2000);
console.log("appslist", data.data.d.results);
$scope.apps = data.data.d.results;
});
};
});
app.config([
'$compileProvider',
function($compileProvider){
$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|chrom-extension|javascript):/)
}
]);
How can I do this?
There's a lot of extraneous code in the controller. For the purposes of this answer I removed it. Also I understand that users and apps are related by a property called Title but the name was confusing me - forgive me if the data doesn't make sense.
Suggestion: Only use $(jQuery) where strictly necessary. Angular provides a lot of functionality that replaces jQuery functionality. Instead of using $.ready like:
$(document).ready(function() {
$scope.getAdminList();
$scope.getAppsList();
});
wait to bootstrap your application until the document is ready using the following code:
(function () {
angular.element(document).ready(function () {
angular.bootstrap(document, ['myApp']);
});
})();
Then you don't have to burden the controller with the responsibility of waiting until the document is loaded. Note: ng-app was removed from the markup.
Suggestion: Use $q.all() to wait for multiple promises to resolve. $q.all() will wait until all promises resolve to call .then(). This helps to ensure that all data is available when you start to use it.
Suggestion: Only assign properties and functions to $scope if they will be used by the view. I removed the functions that are not used by the view from the $scope object.
How does it work?
When the controller loads, we use $q.all() to invoke and wait for fetchAdminList() and fetchAppsList() to fetch data from an API. Once each API request resolves we unwrap the data in .then() callbacks and return it (read more on promise chaining to understand what happens when a value is returned from .then()). When both promises resolve, we store the data on $scope to make it available to the view. We also pre-compute which applications each user can use and store that data in $scope.userApps to make it available to the view.
I did not have access to the APIs you are fetching data from. I substituted $http calls with an immediately resolving promise using $q.resolve() and static data. When you are ready just replace $q.resolve(...) with the original $http(...) calls in the fetch functions.
Run the snippet to see it in action.
var app = angular.module('myApp', []);
(function () {
angular.element(document).ready(function () {
angular.bootstrap(document, ['myApp']);
});
})();
var USERS = [
{
Title: 'Software Engineer',
FirstName: 'C',
LastName: 'Foster',
EmployeeID: 1
},
{
Title: 'Software Engineer',
FirstName: 'J',
LastName: 'Hawkins',
EmployeeID: 2
},
{
Title: 'CEO',
FirstName: 'Somebody',
LastName: 'Else',
EmployeeID: 3
}
];
var APPS = [
{
Application: { Title: 'StackOverflow' },
Title: 'Software Engineer'
},
{
Application: { Title: 'Chrome' },
Title: 'Software Engineer'
},
{
Application: { Title: 'QuickBooks' },
Title: 'CEO'
}
]
app.controller('MainCtrl', function ($scope, $http, $q) {
$q.all({
users: fetchAdminList(),
apps: fetchAppsList()
})
.then(function(result) {
// Store results on $scope
$scope.users = result.users;
$scope.apps = result.apps;
// Pre-compute user apps
$scope.userApps = $scope.users.reduce(
function(userApps, user) {
userApps[user.EmployeeID] = getUserApps(user.Title);
return userApps;
},
[]
);
});
function fetchAdminList() {
return $q.resolve({ data: { d: { results: USERS } } })
.then(function (data) { return data.data.d.results; });
}
function fetchAppsList() {
return $q.resolve({ data: { d: { results: APPS } } })
.then(function (data) { return data.data.d.results; });
}
// Get a list of apps that apply to user title
function getUserApps(userTitle) {
return $scope.apps.filter(function(app) {
return app.Title === userTitle;
});
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.js"></script>
<div>
<div ng-controller="MainCtrl">
<div class="ProfileSheet" ng-repeat="user in users">
<h3 class="heading">User Profile</h3>
<table id="Profile">
<tr>
<th>User</th>
<td>{{user.Title}}</td>
</tr>
<tr>
<th>First Name</th>
<td>{{user.FirstName}}</td>
</tr>
<tr>
<th>Last Name</th>
<td>{{user.LastName}}</td>
</tr>
<tr>
<th>Job Title</th>
<td>{{user.JobTitle}}</td>
</tr>
<tr>
<th>Emp ID</th>
<td>{{user.EmployeeID}}</td>
</tr>
<tr>
<th>Officer Code</th>
<td>{{user.OfficerCode}}</td>
</tr>
<tr>
<th>Email</th>
<td>{{user.Email}}</td>
</tr>
<tr>
<th>Telephone</th>
<td>{{user.WorkPhone}}</td>
</tr>
<tr>
<th>Fax Number</th>
<td>{{user.WorkFax}}</td>
</tr>
<tr>
<th>Location Description</th>
<td>{{user.LocationDescription}}</td>
</tr>
<tr>
<th>Mailstop / Banking Center #</th>
<td>{{user.Mailstop}}</td>
</tr>
</table>
<br>
<h3 class="heading">User Applications</h3>
<div style="border:3px solid #707070; padding-right:12px;">
<h4 style="padding-left:5px;">User Applications</h4>
<table id="Apps">
<tr id="AppsHeading">
<th>Application</th>
<th>User ID</th>
<th>Initial Password</th>
<th>Options / Comment</th>
<th>Setup Status</th>
</tr>
<tr ng-repeat="app in userApps[user.EmployeeID]">
<td>{{app.Application.Title}}</td>
<td>{{app.Title}}</td>
<td>{{app.InitialPassword}}</td>
<td>{{app.OptionsComments}}</td>
<td style="border-right:3px solid #707070;">{{app.SetupStatus}}</td>
</tr>
</table>
</div>
</div>
</div>

angular angular-table dynamic header name

I use angular and angular-table to display multiple tables on the same page.
I need to create dynamic table with dynamic header and dynamic content.
Plunkr her
This is a working example with non dynamic header but I don't find how to make dynamic
The controller :
angular.module('plunker', ['ui.bootstrap',"angular-table","angular-tabs"]);
function ListCtrl($scope, $dialog) {
$scope.cols= ['index','name','email'];
$scope.list = [
{ index: 1, name: "Kristin Hill", email: "kristin#hill.com" },
{ index: 2, name: "Valerie Francis", email: "valerie#francis.com" },
...
];
$scope.config = {
itemsPerPage: 5,
fillLastPage: true
};
}
HTML
<!-- this work -->
<table class="table table-striped" at-table at-paginated at-list="list" at-config="config">
<thead></thead>
<tbody>
<tr>
<td at-implicit at-sortable at-attribute="name"></td>
<td at-implicit at-sortable at-attribute="name"></td>
<td at-implicit at-sortable at-attribute="email"></td>
</tr>
</tbody>
</table>
<!-- this fail ... -->
<table class="table table-striped" at-table at-paginated at-list="list" at-config="config">
<thead></thead>
<tbody>
<tr>
<td ng-repeat='col in cols' at-implicit at-sortable at-attribute="{{col}}"></td>
</tr>
</tbody>
</table>
I am missing some think or it is not possible with this module ?
Did you know another module where you can have dynamic header and pagination ? ( i try also ngTable but have some bug issu with data not being displayed )
Through the below code, you can generate dynamic header
<table class="table table-hover table-striped">
<tbody>
<tr class="accordion-toggle tblHeader">
<th ng-repeat="(key, val) in columns">{{key}}</th>
</tr>
<tr ng-repeat="row in rows">
<td ng-if="!$last" ng-repeat="col in key(row)" ng-init="val=row[col]">
{{val}}
</td>
</tr>
</tbody>
</table>
Angular Script
var app = angular.module('myApp', []);
app.controller('myControl', function ($scope, $http) {
$http.get('http://jsonplaceholder.typicode.com/todos').success(function (data) {
$scope.columns = data[0];
$scope.rows = data;
}).error(function (data, status) {
});
$scope.key = function (obj) {
if (!obj) return [];
return Object.keys(obj);
}
});

Populate and update a table with data from a different table

My site allows for a user to search for a term which returns a table of associated songs. When the "Add Track" button in a particular row is clicked after the search, the respective track name and trackId are added to the table "playlist". The problem I am having is that once "Add Track" is clicked within a different row, the data from that row is not added to the "playlist" table, but rather it just replaces the previous information. I need to be able to generate a cumulative table. Any help would be great and thanks in advance!
<body ng-app>
<body ng-app>
<div ng-controller="iTunesController">
{{ error }}
<form name="search" ng-submit="searchiTunes(artist)">
<input type="search" required placeholder="Artist or Song" ng-model="artist"/>
<input type="submit" value="Search"/>
</form>
<div class="element"></div>
<table id="SongInfo" ng-show="songs">
<thead>
<tr>
<th>Album Artwork</th>
<th>Track</th>
<th></th>
<th>Track Id</th>
<th>Preview</th>
<th>Track Info</th>
<th>Track Price</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="song in songs">
<td><img ng-src="{{song.artworkUrl60}}"
alt="{{song.collectionName}}"/>
</td>
<td>{{song.trackName}}</td>
<td><button ng-click="handleAdd(song)">Add Track</button></td>
<td>{{song.trackId}}</td>
<td>Play</td>
<td>View Track Info</td>
<td>{{song.trackPrice}}</td>
</tr>
</tbody>
</table>
<table id="playlist">
<thead>
<tr>
<th>Playlist</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="song in addedtracks">
<td>{{song.trackName}}</td>
<td>{{song.trackId}}</td>
</tr>
</tbody>
</table>
</div>
</body>
itunes_controller.js
var iTunesController = function($scope, $http){
$scope.searchiTunes = function(artist){
$http.jsonp('http://itunes.apple.com/search', {
params: {
'callback': 'JSON_CALLBACK',
'term': artist,
limit: 5,
}
}).then(onSearchComplete, onError)
}
$scope.handleAdd = function(song) {
// this song object has all the data you need
console.log("handle add ", song)
$scope.addedtracks = [{song:'trackName', song:'trackID'}]
$scope.addedtracks.push(song)
}
var onSearchComplete = function(response){
$scope.data = response.data
$scope.songs = response.data.results
}
var onError = function(reason){
$scope.error = reason
}
}
I saw some issues with your code. First the code below
$scope.addedtracks = [{song:'trackName', song:'trackID'}]
$scope.addedtracks.push(song)
Acording to your html, you are passing the song object to the handleAdd. So just remove the first line from code above. After that step, declare addedtracks array before handleAdd like below
$scope.addedtracks = [];
Modify the ng-repeat for the playlist like below:
<tr ng-repeat="song in addedtracks track by $index">
<td>{{song.trackName}}</td>
<td>{{song.trackId}}</td>
</tr>
And that's it. Note that I used track by $index because ngRepeat does not allow duplicate items in arrays. For more information read Tracking and Duplicates section.
Finally this is working plunker

Dynamically setting new ng-model when pushing model to array

Can't figure out how to dynamically add a new model whenever a new row is added to the page. For example, the input select box ng-model= infos.rigBonusInfo.rigName is used for all select box I've added to the page. I would like to have a different model attached to a each select inputs. I tried using ng-model= infos.rigBonusInfo.rigName[rigBonus] but it doesn't work for the rates as the same model gets attachedto each rate field.
Pretty much what I want to do is to bind a new model whenever a new row gets pushed into the array.
Currently, I have a nested table which is the following:
<div class="col-lg-5">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Rig</th>
<th>Rig Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="rig in rigs">
<td>{{ $index + 1 }}</td>
<td>{{ rig.name }}</td>
</tr>
</tbody>
</table>
</div>
<div class="col-lg-2"></div>
<div class="col-lg-5">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Bonus Name</th>
<th>Rate</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="bonus in create.rigBonusRates">
<td>{{ bonus.rateName }}</td>
<td>{{ bonus.rate }}</td>
</tr>
</tbody>
</table>
</div>
<table>
<thead>
<tr>
<th>Date</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="rigDate in rigDateList track by $index">
<td><input ui-date="datepickerOptions" ng-model="date" /></td>
<td>
<table>
<thead>
<tr>
<th>Rig</th>
<th>Rate1</th>
<th></th>
<th>Rate2</th>
<th></th>
<th>Rate3</th>
<th></th>
<th>Rate4</th>
<th></th>
<th>Comments</th>
</tr>
</thead>
<tr ng-repeat="rigBonus in rigBonusList track by $index">
<td><select ng-options="rig as rigs.indexOf(rig) + 1 for rig in rigs" ng-model="infos.rigBonusInfo.rigName[rigBonus]" ></select></td>
#for (var i = 1; i < 5; i++)
{
<td><select ng-options="rigBonus.rateName for rigBonus in create.rigBonusRates" ng-model="infos.rigBonusInfo.rate#(#i)"></select></td>
<td><input type="text" ng-disabled="infos.rigBonusInfo.rate#(#i).rateName != 'Special' " ng-model=infos.rigBonusInfo.rate#(#i).rate /></td>
}
<td><input ng-model="info.rigBonusInfo.comments" /></td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
<div>
<button type="button" ng-click="add()">Add</button>
<button type="button" ng-click="addDate()">Add Date</button>
</div>
My current controller has the following:
angular.module('RigBonus').controller('rigCreateController', ['$scope', '$http', 'PayPeriodService', 'RigLegendService',
function ($scope, $http, PayPeriodService, RigLegendService, RigBonusRateService) {
$scope.rigs = RigLegendService.getRigLegend();
$scope.datepickerOptions = {
orientation: 'top',
startDate: PayPeriodService.getStartDate(),
endDate: PayPeriodService.getEndDate()
};
$http({ method: 'GET', url: '/Home/CreateData' }).success(function (data) {
$scope.create = data;
$scope.infos = {
rigBonusInfo: {
rigName: $scope.rigs[0],
rate1: $scope.create.rigBonusRates[0],
rate2: $scope.create.rigBonusRates[0],
rate3: $scope.create.rigBonusRates[0],
rate4: $scope.create.rigBonusRates[0],
comment: ""
}
};
$scope.add = function () {
$scope.rigBonusList.push();
};
$scope.addDate = function(){
$scope.rigDateList.push("");
};
});
$scope.rigBonusList = [$scope.rigBonusInfo];
$scope.rigDateList = [];
$scope.submit = function () {
$http.post('/Home/Create', {model: "testing"} );
};
}]);
I figured out my issue. My problem was that I was not sure how to generate a new object when a new row of controls are added. Think I should have put something on fiddleJS to help people visualize it better. As a static model was used ($scope.infos) as ng-model, the same model was used for two different controls which I don't want. I want all my controls to be unique.
The fix was to create the object I had in mind which is the following:
$scope.rigDateList = [{
date: "",
rigBonusList: [{}]
}];
So it is an array of objects where the object contains a date and another array of objects.
When I want to push new objects to the inside array which I didn't know I could just create objects like this at the time. I was trying to figure out a way to dynamically create new models ng-model could by declaring them in the controller. I use the following function:
$scope.rigDateList[$scope.rigListIndex].rigBonusList.push({
rigName: "",
rate1: "",
rate2: "",
rate3: "",
comments: ""
});
I also didn't know that I could use elements inside the array from ng-repeat. In the following case, it is rigBonus that I could have used as a model instead of infos model.
<tr ng-repeat="rigBonus in rigDate.rigBonusList track by $index">
<td><select ng-options="rig as rigs.indexOf(rig) + 1 for rig in rigs" ng-model="rigBonus.rigName"></select></td>
and when I want to push to the outside array I use the following:
$scope.rigDateList.push({
date: "",
rigBonusList: [""]
});
$scope.rigListIndex = $scope.rigListIndex + 1;
I use an index to keep track of which object I'm in.
A more closest question and answer is that:
Ng-repeat with dynamic ng-model on input not working
please, take a look.

knockout js showing related objects(selected id) on click

I'm new to Knockout js and need some advice. What I am trying to do (the correct way) is have orders listed in a grid and a "production" button that when it is click, will show only the production objects that have matching id's to the order id. I'm trying to wrap my head around Knockouts binding, but I think I am over thinking things.
right now I have 2 objects Order and Production with are observable arrays filled with observables. Order has value of orderId and Production have value of prodId that I am checking for a match. I'm now wondering if I should not make this on object with mutli-dimensional array. Would it be easier to show selected data that way?
here is an example of the initial arrays
var initProduction = [
new Production({
proId:"183175",
pType:"Art TIme",
startTime:"11:20",
stopTime:"11:50",
totalTime:"",
by :"MJ"
})
var initData = [
new Order({
date:"06-09-2014",
orderId:"183175",
name:"Columbus Africentric",
dateRec:"05-23-2014",
rushDate:"",
totalQty:55,
parts:"1",
auto:"No",
type:"Local",
})
]
so should I combine into a multidimensional array? And if so, how would I do that? And how would I create a click event to show related data in another table showing only the production info.
I hope this makes sense and someone can help me. I apologize for my ignorance.
here is a stripped down version of my html bindings
<table>
<tbody data-bind="foreach:filteredOrders">
<tr>
<td>
<label class="read" data-bind="text:orderId, visible:true" />
</td>
<!-- controls -->
<td class="tools">
<button class="button toolButton" data-bind="click: $root.showSummary">Show Production</button>
</td>
</tr>
</tbody>
</table>
<h3>Production Summary</h3>
<table class="ko-grid" id="menu" >
<tbody data-bind="foreach:filteredProds">
<tr>
<td>
<div>
<label class="read" data-bind="text:proId, visible:true" />
</div>
</td>
</tr>
</tbody>
</table>
I would just have an orders array and then link the production object to the order.
var model = {
orders: [
{
date:"06-09-2014",
orderId:"183175",
name:"Columbus Africentric",
dateRec:"05-23-2014",
rushDate:"",
totalQty:55,
parts:"1",
auto:"No",
type:"Local",
production: {
proId:"183175",
pType:"Art TIme",
startTime:"11:20",
stopTime:"11:50",
totalTime:"",
by :"MJ"
}
},
{
date:"06-09-2014",
orderId:"183176",
name:"Angle Africentric",
dateRec:"05-23-2014",
rushDate:"",
totalQty:55,
parts:"1",
auto:"No",
type:"Local"
}
]
};
In the above json the second order doesn't have a production object.
Then in the viewModel I would use a computed which will return the orders depending on if all orders or only production orders should be shown. I've created a toggle here which is linked to the button.
var ViewModel = function (model) {
var self = this;
self.orders = $.map(model.orders, function (order) { return new Order (order); });
self.toggleProductionMode = function (order) {
order.showProductionOrder(!order.showProductionOrder());
};
};
var Order = function (order) {
var self = this;
ko.utils.extend(self, order);
self.showProductionOrder = ko.observable(false);
};
View:
<table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
</thead>
<tbody data-bind="foreach: orders">
<tr>
<td data-bind="text: orderId"></td>
<td data-bind="text: name"></td>
<td data-bind="if: production"><button data-bind="click: $root.toggleProductionMode">Toggle Production Orders</button>
</td>
</tr>
<tr data-bind="visible: showProductionOrder, with: production">
<td colspan="3">
<table>
<tr>
<th>proId</th>
<th>pType</th>
</tr>
<tr>
<td data-bind="text:proId"></td>
<td data-bind="text:pType"></td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
Demo here: http://jsfiddle.net/X3LR6/2/

Resources