Populate and update a table with data from a different table - arrays

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

Related

Set all checkboxes to checked as default with Checklist-model

I am using Checklist-model to display some data with checkboxes. The data is provided as the result of a promise. The list is populating but I want to set all of the checkboxes to checked as default. How can I accomplish this?
Here is my code:
datas.getRules().then(
function (resRules)
{
$scope.rules = resRules.data._embedded.rules;
$scope.versionForm.ignoreRule = $scope.rules.map(r => r.id);
console.log($scope.versionForm.ignoreRule);
},
function (resRulesErr)
{
console.log(resRulesErr);
}
);
<table class="table">
<thead>
<tr>
<th>Include</th>
<th>Rule</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="r in rules track by $index">
<td><input type="checkbox" checklist-model="versionForm.ignoreRule" checklist-value="r.id" />
</td>
<td>{{r.expression}}</td>
</tr>
</tbody>
</table>
When $scope.versionForm.ignoreRule prints to console, it shows [64, 67, 18].
Few issues with your code:
$scope.versionForm.ignoreRule = $scope.rules.map(r => r.id);
it should be
$scope.versionForm.ignoreRule = $scope.rules;
You want to use an array of rules(objects) but you actually have in there an array of ids.
<tr ng-repeat="r in rules track by $index">
it should be
<tr ng-repeat="r in rules track by r.id">
and you have to ensure that the id is unique.

Angular loop through table row and check for checked checbox

I have a table that has a list from database with checkbox on each row, checkbox will used for ex. during deletion of the record.
So what i am trying to achieve is that when i clicked the delete button, angular will loop each row in table and check the checkbox whether is checked, if yes the please proceed to delete. Dont have any idea how to do this. Someone please give some related example.
Here is my code
index.html
<button class="ui red labeled icon button right floated" type="button" data-content="Delete selected item(s)" id="delete" ng-click="deleteSeleted()"><i class="trash icon"></i>Delete</button>
<div class='container-table'>
<table class="ui fixed single line celled table striped sortable compact" style="width:2000px" id="mytable">
<thead>
<tr>
<th class="width-checkbox"><input type="checkbox" ng-model="matin.selectedAll" /></th>
<th class="width-120">Item</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="x in data">
<td><input type="checkbox" ng-checked="matin.selectedAll"></td>
<td>{{x.item}}</td>
</tr>
</tbody>
</table>
</div>
<tr ng-repeat="x in data">
<td><input type="checkbox" ng-model="x.selected"></td>
<td>{{x.item}}</td>
</tr>
Angular Js Code
for (var k = 0; k < $scope.data.length; k++)
{
if($scope.data[k].selected==true)
{
//Perform your desired thing over here
var val=$scope.data[k].item //to getData
}
}
Please find the fiddler link which i have created to select all the items in the table and on delete print which ever is checked https://jsfiddle.net/dfL1L944/3/
var appModule = angular.module('Module', []);
appModule.controller("DataController", function($scope) {
$scope.data = [{"name":"Alex"},{"name":"Juni"}]
$scope.deleteAll = false;
$scope.deleteSeleted = function(){
$scope.data.forEach(function(x) {
console.log(x.name);
});
}
$scope.selectedAll = function(){
$scope.data.forEach(function(x) {
if($scope.deleteAll){
x.deleted = true;
}
else{
x.deleted = false;
}
});
}
});
HTML Code
<div ng-app="Module"> <div ng-controller="DataController">
<button class="ui red labeled icon button right floated" type="button" data-content="Delete selected item(s)" id="delete" ng-click="deleteSeleted()"> <i class="trash icon"></i>Delete</button> <div class='container-table'> <table class="ui fixed single line celled table striped sortable compact" style="width:200px" id="mytable"> <thead>
<tr>
<th width="20px">
<input type="checkbox" ng-model="deleteAll" ng-click="selectedAll()" /></th>
<th>Item</th>
</tr> </thead> <tbody>
<tr ng-repeat="x in data">
<td width="2px"><input type="checkbox" ng-checked="x.deleted"></td>
<td>{{x.name}}</td>
</tr> </tbody> </table> </div>
</div> </div>
You could use $filter (you would need to insert $filter as a dependency)
$scope.data: [ // assuming your model looks like this
{
Id: "my_id",
Name: "my_name",
checked: true
}
];
var myFilteredValues = $filter('filter')($scope.data, { $: true });
And in your HTML
<tr ng-repeat="x in data">
<td><input type="checkbox" ng-model="x.checked"></td>
<td>{{x.Name}}</td>
</tr>
You can add a .toDelete property to every x in your data array, for example, and bind the checkboxes like this:
<input type="checkbox" ng-model="x.toDelete">
Afterwards you can create a button under the table:
<input type="button" ng-click="deleteRows();" value="Delete rows">
...And then create a function on your controller's scope (a newbie-friendly function):
$scope.deleteRows = function(){
var i=0;
for(i=0; i<data.length; i++){
if(data[i].toDelete){
//send your server requests here and do
//your stuff with the element if needed
data.splice(i, 1); //remove the element from the array
i--; //decrement the value of i so it stays the same
//(array is now shorter than it used to be)
}
}
}
You can also keep the information on what row is to be deleted in a separate array on the same scope but this solution seems simpler to me.
Regarding the "Check All" checkbox at the top, you can create a function and bind it with ng-click to a button or any other element and use that function to simply iterate through all the elements and set the .toDelete property to true for each one of them.

How to use ng-repeat for array in array using single ng-repeat

I got a json of table which has columns and rows as below
$scope.table = {
Columns: [{Header:"22-Jul-15",SubHeaders: ["10:33 AM"]}
, {Header:"21-Jul-15",SubHeaders: ["03:40 AM"]}
, {Header:"17-Jul-15",SubHeaders: ["01:05 PM", "12:06 PM"]}]
, Rows:[{Items:[{Value:1},{Value:5},{Value:8},{Value:""}]}
,{Items:[{Value:2},{Value:6},{Value:9},{Value:""}]}
,{Items:[{Value:3},{Value:7},{Value:10},{Value:15}]}]
} //end of table
I want to display Columns.SubHeaders as Sub header row of a table.
Here what I tried, but did not work
<table class="table table-stripped table-bordered">
<thead>
<tr>
<th ng-repeat="col in table.Columns" colspan="{{col.SubHeaders.length}}">{{col.Header}}</th>
</tr>
<tr>
<td class="center text-black" ng-repeat="head in table.Columns[0].SubHeaders">{{head}}</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in table.Rows">
<td ng-repeat="item in row.Items">
{{item.Value}}
</td>
</tr>
</tbody>
</table>
I used head in table.Columns[0].SubHeaders just to show it is working for hard-coded index value.
How can I achieve this using single ng-repeat? I can use two ng-repeats but it will lead to unnecessary html markup.
Here is the complete fiddle
I created this fiddler (forked from yours):
https://jsfiddle.net/b50hvzef/1/
The idea is to join the subheaders as they are they actual columns:
<td class="center text-black" ng-repeat="head in subHeaders">{{head}}</td>
and the code looks like this:
var app = angular.module("app",[]);
app.controller("MyController", function ($scope, $http) {
$scope.table = {
Columns: [{Header:"22-Jul-15",SubHeaders: ["10:33 AM"]}
, {Header:"21-Jul-15",SubHeaders: ["03:40 AM"]}
, {Header:"17-Jul-15",SubHeaders: ["01:05 PM", "12:06 PM"]}]
,Rows:[{Items:[{Value:1},{Value:5},{Value:8}]}
,{Items:[{Value:2},{Value:6},{Value:9}]}
,{Items:[{Value:3},{Value:7},{Value:10}]}]
};
var subHeaders = [];
$scope.table.Columns.forEach(function(col) {
col.SubHeaders.forEach(function(subHeader) {
subHeaders.push(subHeader);
});
});
$scope.subHeaders = subHeaders;
});
Note that there is still a mismatch between columns and data. But it's up to you how to solve it.
Hope this helps.

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