Dynamically updating ng-repeat for matrix - angularjs

I have matrix(2D array) cells in model, what I represent in a table.
<tr ng-repeat='row in cells track by $index'>
<td ng-repeat='cell in row track by $index'>
{{cell}}
</td>
</tr>
I want add a drop down buttons to resize length and width,
<select ng-model="length" >
<option ng-repeat="size in sizes" ng-click="setLength(size)">{{size}} </option>
</select>
but can't refresh ng-repeat. For refresh page I use $scope.$apply() after set new matrix in cells
$scope.cells = new Array($scope.width);
for (var i = 0; i < $scope.cells.length; i++) {
$scope.cells[i] = new Array($scope.length);
for (var j = 0; j < $scope.length; j++) {
$scope.cells[i][j] = 'cell';
}
}
$scope.$apply();
but it doesn't help. How to refresh ng-repeat?
P.S. When user is changing size matrix, it should back to default values with new size.
my demo is here

In your fiddle your 2D array is not created corretly. Please have a look at this SO question for tips how to setup the array.
I've changed these points of your code:
used ng-options for length and width dropdown. That's easier than ng-repeat.
Removed click events from the width and length drop down and added a $watch for width and length scope variables for updating the map.
Updated creation of 2d array.
Below is a working demo of your code or in this fiddle.
var myapp = angular.module('mapApp', []);
myapp.controller('editorController', function ($scope) {
$scope.cells = [
[]
];
$scope.sizes = [];
makeSizes();
$scope.length = $scope.sizes[0];
$scope.width = $scope.sizes[0];
$scope.$watch('[width,length]', makeMap, true);
function makeMap() {
var cols = $scope.width,
rows = $scope.length;
console.log('makeMap');
$scope.cells = matrix(rows, cols, 'cell');
}
function matrix(rows, cols, defaultValue) {
// code from here https://stackoverflow.com/questions/966225/how-can-i-create-a-two-dimensional-array-in-javascript
var arr = [[]];
// Creates all lines:
for (var i = 0; i < rows; i++) {
// Creates an empty line
arr[i] = [];
// Adds cols to the empty line:
arr[i] = new Array(cols);
for (var j = 0; j < cols; j++) {
// Initializes:
arr[i][j] = defaultValue;
}
}
return arr;
}
makeMap();
function makeSizes() {
for (var i = 0; i < 5; i++) {
$scope.sizes.push(i + 3);
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="mapApp" ng-controller="editorController">
<label>Length</label>
<select ng-model="length" ng-options="length for length in sizes">
</select>
<table>
<label>Width</label>
<select ng-model="width" ng-options="width for width in sizes">
</select>
<table>
<tbody>
<tr ng-repeat="row in cells track by $index">
<td ng-repeat="cell in row track by $index">
{{cell}}
</td>
</tr>
</tbody>
</table>
</div>

Related

Get filtered value from view to controller

I use ng-repeat to show my array of objects. One of the attributes is video duration, and I used filter to directly show sum of all meta_durations. here is filter
app.filter('sumProduct', function() {
return function (input) {
var i = input instanceof Array ? input.length : 0;
var a = arguments.length;
if (a === 1 || i === 0)
return i;
var keys = [];
while (a-- > 1) {
var key = arguments[a].split('.');
var property = getNestedPropertyByKey(input[0], key);
if (isNaN(property))
throw 'filter sumProduct can count only numeric values';
keys.push(key);
}
var total = 0;
while (i--) {
var product = 1;
for (var k = 0; k < keys.length; k++)
product *= getNestedPropertyByKey(input[i], keys[k]);
total += product;
}
return total;
function getNestedPropertyByKey(data, key) {
for (var j = 0; j < key.length; j++)
// data = dataDuration[key[j]];
data = data.meta_duration;;
return data;
}
}
})
and in view
<table>
<thead>
<tr>
<th>Media name</th>
<th>Media type</th>
<th>Media duration in sec</th>
<th>Media thumbnail</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="media in myMediaItems">
<td>{{media.name}}</td>
<td>{{media.type}}</td>
<td>>{{media.meta_duration}}</td>
<td><img src="{{media.thumbnail}}" alt="" /></td>
</tr>
</tbody>
<tr>
<td></td>
<td></td>
<td>Total duration {{ myMediaItems|sumProduct:'duration' }}</td> //here is where i use custom filter
<td></td>
</tr>
</table>
How to get total duration value in the controller?
Dynamically i add (push) media to list from another list with all media.
$scope.addToMediaList = function(item) {
var seconds = parseInt(item.meta_duration);
$scope.view_duration = Math.floor(moment.duration(seconds,'seconds').asHours()) + ':' + moment.duration(seconds,'seconds').minutes() + ':' + moment.duration(seconds,'seconds').seconds();($scope.view_duration_seconds, "HH:mm:ss");
$scope.myMediaItems.push(item);
$scope.sumDuration = $filter("sumProduct")(myMediaItems.meta_duration); //i try like this, set on $scope.sumDuration but in conole i get only number 0
$scope.myMediaItemsId.push(item.id);
$scope.input = "";
};
Thanks
I simplified your filter.
try this
app.filter('sumProduct', function() {
return function (input) {
var i = input instanceof Array ? input.length : 0;
var a = arguments.length;
if (i === 0)
return i;
var total = 0;
for(var x of input){
var duration = parseFloat(x.meta_duration);
if(isNaN(duration)){
throw 'filter sumProduct can count only numeric values';
}
total += duration;
}
return total;
}
});
You can use something like this
<div ng-init="sumDuration = myMediaItems|sumProduct:'duration'"> </div>
I solved this by forwarding the returned value from the custom filter to controller.
var filtered = $filter('sumProduct')($scope.myMediaItems);
console.log(filtered)
Filtered value is sum. thnx # Amaya San

Calculate the Sum of Values using ng-repeat in Angular js

I am newbie to Angular js.I am just trying to calculate the sum of Values of each row using angular js.Here, I am dynamically adding and removing rows.
For Eg: Let's say first row value is 30, Now I added one row with value 30, then total should be show 60 like this.
1. 30
2. 30
3. 50
Total 120
HTML Code:
<table id="t1" style="border:none;">
<tr><th>Start</th><th>Stop</th><th>Downtime(In Min)</th><th>Reason</th></tr>
<tr ng-repeat="item in invoice">
<td><input type="text" required ng-model="$invoice.start" name="r1[]"></td>
<td><input type="text" required ng-model="$invoice.stop" name="r2[]" ng-blur="diff($invoice)"></td>
<td><input type="text" name="r3[]" ng-model="$invoice.diff"/></td>
<td style="border:none;"><a href ng-click="remove(item)">X</a></td>
</tr>
<tr style="border:none;">
<td style="border:none;"><a href ng-click="add()">+</a></td>
</tr>
</table>
<span class="labelCode">Total Downtime</span><input required type="text" name="Tot_D" ng-value="d1()"/></span></br>
Angular JS:
$scope.d1=function(){
var total = 0;
for(var i = 0; i < $scope.invoice.length; i++){
var product = $scope.invoice[i];
total += parseInt(product.diff);
}
return total;
}
//Calculate the Difference between two times
$scope.diff = function(item) {
item.diff = computeDiff(item.start,item.stop);
}
function computeDiff(start, stop) {
if (start && stop) {
var s_hr = start.split(":")[0];
var s_min = start.split(":")[1];
var e_hr = stop.split(":")[0];
var e_min = stop.split(":")[1];
return Math.abs((parseInt(e_hr) - parseInt(s_hr)) * 60) + Math.abs(parseInt(e_min) - parseInt(s_min))
}
}
Now, it just showing NaN. I don't know what is wrong.
Please help out.Thanks in advance.

ng-repeat filter not working when range of the array is used

The array 'response' is what I get from my .php file
$http.get(encodedpage).success(function(response) {
$scope.friends = response;
}
It has a bunch of values and the filter is working correct
<input type="search" ng-model="q" />
<div class="animate-repeat" ng-repeat="x in friends | filter:q as results">
{{x.name}}
</div>
When I want to just show a range of it, the filter is not working anymore.
Although everything is displayed and shown correctly.
$http.get(encodedpage).success(function(response) {
for (var i = 0; i < 3; i++) {
$scope.friends[i] = response[i];
}
}
I am giving up why.
here is a jsfiddle example
http://jsfiddle.net/U3pVM/11646/
The problem is with the array declaration. Looks like you have declared it as an object and try to set elements into it.
$scope.friendsReduced = [];
for (var i = 0; i < 2; i++) {
$scope.friendsReduced[i] = $scope.friends[i];
}
Jsfiddle is updated for your reference.

Nested ng repeat failure in angular js

Try to do a nest ng-repeat, parent ng-repeat works but not for its child
1.Created object and insert data when app init
2.display data by calling ng-repeat
angular.module('lipapp', []).controller('lipapp_Module_Control', function ($scope, $http, $window) {
$scope.CompaignBasket = [];
$scope.CompaignBasketTotal = 0;
$scope.CompaignBasketCauseTotal = [];
//Sample Data Section, Real data plz go to $scope.UpdateCompaign function
$scope.InitialCompaignBasket = function () {
$scope.CompaignBasket = [];
var causeAmount = [];
var causeitem = 0;
var donorDetail = {};
donorDetail.Date = '2/14/13';
donorDetail.Donor = 'George Smith';
donorDetail.City = 'Los Angelos';
donorDetail.State = 'CA';
donorDetail.Total = 400;
causeAmount = []; //forloop Dynamic Insert!
causeAmount.push(10);
causeAmount.push(0);
causeAmount.push(500);
causeAmount.push(0);
causeAmount.push(1000);
causeAmount.push(0);
//causeitem = 0;causeAmount.push(causeitem); or I should use this format?
donorDetail.DonorCauseAmount = causeAmount;
$scope.CompaignBasketTotal += donorDetail.Total;
$scope.CompaignBasket.push(donorDetail);
console.log( $scope.CompaignBasket);
...
}
All the result display correctly but the item.donorCauseAmount has throw errors
<tr ng-repeat="item in CompaignBasket">
<td>{{item.Date}}</td>
<td>{{item.Donor}}</td>
<td>{{item.City}}</td>
<td>{{item.State}}</td>
<td ng-repeat="cause_item in item.DonorCauseAmount">{{cause_item}} </td>
<td>${{item.Total|number :0}}</td>
</tr>
Also for when I try to calculate the total for different CauseItem in the same col in script there is also a repeater error
for(var i=0; i< $scope.CompaignBasket.length; i++)
{
if (i == 0)
{
$scope.CauseTotalAmount = $scope.CompaignBasket[i].DonorCauseAmount;
console.log($scope.CauseTotalAmount);
}
else {
for (var j = 0; j < $scope.CauseTotalAmount.length; j++) {
// $scope.CauseTotalAmount[j] += $scope.CompaignBasket[i].DonorCauseAmount[j];
console.log('total '+ $scope.CompaignBasket[i].DonorCauseAmount[j]); //Error show up by this!!!
}
}
console.log($scope.CauseTotalAmount);
}
How can I solve it?
You need to use a track by index when you have duplicate values within the array.
<td ng-repeat="cause_item in item.DonorCauseAmount track by $index">{{cause_item}} </td>

AngularJs ng-repeat change loop increment

I'm newbie to AngularJs. I want to use ng-repeat as for(i=0; i < ele.length; i+=2)
I have a table with 4 columns, where I'm going to use ng-repeat
<table>
<tr ng-repeat="i in elements">
<th>{{i.T}}</th>
<td>{{i.V}}</td>
<th>{{elements[($index+1)].T}}</th> <!-- This should be next element of the elements array -->
<td>{{elements[($index+1)].V}}</td> <!-- This should be next element of the elements array -->
</tr>
</table>
I need to access 2 elements in a single iteration and iteration increment should be 2
I hope this make sense. Please help me.
Please check this html view Plunker
You can create a filter that creates an even copy of the array:
.filter("myFilter", function(){
return function(input, test){
var newArray = [];
for(var x = 0; x < input.length; x+=2){
newArray.push(input[x]);
}
return newArray;
}
});
JsFiddle: http://jsfiddle.net/gwfPh/15/
So if I understand correctly you want to walk your list and alternate th and td's while iterating.
If so you could use a ng-switch:
<table>
<tr ng-repeat="i in elements" ng-switch on="$index % 2">
<th ng-switch-when="0">{{i.T}}</th>
<td ng-switch-when="1">{{i.V}}</td>
</tr>
</table>
See Plunker here
One solution I can think of involves a change in the data model
Template
<table ng-app="test-app" ng-controller="TestCtrl">
<tr ng-repeat="i in items">
<th>{{i.T1}}</th>
<td>{{i.V1}}</td>
<th>{{i.T2}}</th>
<td>{{i.V2}}</td>
</tr>
</table>
Controller
testApp.controller('TestCtrl', ['$scope', function($scope) {
var elements=[]; //This is the dynamic values loaded from server
for (var i = 0; i < 5; i++) {
elements.push({
T : i,
V : 'v' + i
});
}
//A converter which convert the data elements to a format we can use
var items = [];
var x = Math.ceil(elements.length / 2);
for (var i = 0; i < x; i++) {
var index = i * 2;
var obj = {
T1 : elements[index].T,
V1 : elements[index].V
}
if (elements[index + 1]) {
obj.T2 = elements[index + 1].T;
obj.V2 = elements[index + 1].V
}
items.push(obj)
}
$scope.items = items;
}]);
Demo: Fiddle
Another slightly different approach can be found here.

Resources