I'm trying to make a table footer auto-update but the ng-repeat and even the regular double-braces does not appear to auto-bind when the $scope value is updated.
https://jsfiddle.net/r0pk793e/3/
Specifically, I'm setting the value $scope.hello and incrementing it when the table updates (when the user changes a value in the table cells). Though I can see the value changes, it does not get re-bound to the HTML.
I believe this table should be updated by the following function, but it is not...
<table class="tg">
<tr>
<td class="tg-yw4l" ng-repeat="item in items">{{item}}</td>
</tr>
</table>
The $scope.hello does change, as illustrated by the console.log($scope.hello);
var doUpdate = function () {
var items = [];
for (var c = 0; c < headings.length; c++) {
if (typeof (hot.getDataAtCell(0, c)) == "number") {
var levelTotal = 0;
var i = 0;
do {
levelTotal += hot.getDataAtCell(i, c);
i++;
} while (hot.getDataAtCell(i, c) != null);
items.push(levelTotal);
}
else
{
items.push(' ');
}
}
$scope.items = items;
$scope.hello = $scope.hello + 1;
console.log($scope.hello);
}
When I tested your fiddle everything got updated
anyway if this still not working call $scope.$apply(); after updating your values and you will see the magic happening.
Related
This was my previous solution to get info from a json but I want to do it so that I print out a table and show the info, and only update the changes in the code, but not all in the table. Right now, when one person update it changes for all.
app.controller('list', function($scope, $http, $interval) {
$interval(function () {
$http.get('http://localhost/mvcang/list_it/sell/SWISH')
.then(function(data) {
if($scope.phones != data.data){
data = data.data;
$scope.phones = data;
}
});
}, 500);
});
So, it should look like this:
<table>
<tr>
<td>value</td>
<td>value2</td>
<td>value3</td>
</tr>
<tr>
<td>value</td>
<td>value2</td>
<td>value3</td>
</tr>
</table>
If a value in number one value is changed just update that, but not the whole thing, and if its something new, then add it to the list in the order it prints out.
i = 0;
var arr = this.old.split(', ');
angular.forEach($scope.phones, function(value, key){
if(arr[i] != value.data.profile.username ){
this.customHtml += '<li>' + value.data.profile.username + '</li>';
this.old += ', '+value.data.profile.username;
}
i++;
});
Here's something I thought of but can't integrate, or rethink the whole.
<tr ng-repeat="thing in things| filter: {toDpt: filterReceived} && {fromDpt: filterSent}">
I'm trying to show things from AND to my department(dpt). My filterReceived and filterSent are being toggled with two buttons. Both are working.
The problem is: only the first filter is working. If I put fromDpt before toDpt, only fromDpt will work.
Thanks for any advice.
The goal os this code was to display tickets from department or to deparment. The $scope.filters contains the filters to be applied. A user can see, simultaneously or not, tickets that his department has sent or received.
Using Angular Filters, I was able to call my ticketsFilter function, passing in the tickets as the first default argument and filters as second optional argument.
Controller:
$scope.filters.toDpt = 'Finance';
$scope.filters.fromDpt = 'Food';
Filter:
app.filter('ticketsFilter', function (){
return function (items, filters){
console.log
var filtered = [];
for (var i=0; i < items.length; i++){
var item = items[i];
//CHECKING FROM AND TO DPT.
if (item.fromDpt == filters.sent){
filtered.push(item);
} else if (item.toDpt == filters.received){
filtered.push(item);
};
};
return filtered;
};
});
Markup:
<tr ng-repeat="ticket in tickets | ticketsFilter:filters">
Seems like a simple problem though but finding it hard to fix.
There is a pagination component, that has a button & a dropdown. User can go to a page by either clicking the button or selecting that page number in dropdown.
The problem is, when I select a value in the dropdown, nothing happens. Because the scope variable doesnt change from the previous one.
aspx:
<div data-ng-app="app" data-ng-controller="ReportsCtrl">
<div id="paging-top">
<div>
<ul>
<li>
<select data-ng-model="SelectedPage" data-ng-change="ShowSelectedPage();"
data-ng-options="num for num in PageNumbers track by num">
</select>
</li>
<li data-ng-click="ShowNextPage();">Next</li>
</ul>
</div>
</div>
app.js
var app = angular.module("app", ["ngRoute"]);
ReportsCtrl.js
app.controller("ReportsCtrl", ["$scope","ReportsFactory",function ($scope,ReportsFactory) {
init();
var init = function () {
$scope.ShowReport(1);
}
$scope.ShowReport = function (pageNumber) {
GetUserResponsesReport(pageNumber);
}
function GetUserResponsesReport(pageNumber) {
$scope.UserResponsesReport = [];
var promise = ReportsFactory.GetReport();
promise.then(function (success) {
if (success.data != null && success.data != '') {
$scope.UserResponsesReport = success.data;
BindPageNumbers(50, pageNumber);
}
});
}
function BindPageNumbers(totalRows, selectedPage) {
$scope.PageNumbers = [];
for (var i = 1; i <= 5 ; i++) {
$scope.PageNumbers.push(i);
}
$scope.SelectedPage = selectedPage;
}
$scope.ShowSelectedPage = function () {
alert($scope.SelectedPage);
$scope.ShowReport($scope.SelectedPage);
}
$scope.ShowNextPage = function () {
$scope.SelectedPage = $scope.SelectedPage + 1;
$scope.ShowReport($scope.SelectedPage);
}
}]);
Say, the selected value in dropdown is 1. When I select 2 in the dropdown, the alert shows1. When Next is clicked, the dropdown selection changes to 2 as expected. Now, when I select 1 in the dropdown, the alert shows 2.
Tried to make a fiddle, but do not know how to do with a promise - http://jsfiddle.net/bpq5wxex/2/
With your OP SelectedPage is just primitive variable.
With every angular directive new scope is get created.
So,SelectedPage is not update outside the ng-repeat scope after drop-down is changed i.e. in parent scope which is your controller.
In order to do this,use Object variable instead of primitive data types as it update the value by reference having same memory location.
Try to define SelectedPage object in controller in this way.
$scope.objSelectedPage = {SelectedPage:''};
in HTML
<select data-ng-model="objSelectedPage.SelectedPage" data-ng-change="ShowSelectedPage();"
In ShowSelectedPage
$scope.ShowSelectedPage = function () {
console.log($scope.objSelectedPage.SelectedPage);
$scope.ShowReport($scope.objSelectedPage.SelectedPage);
}
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>
I used ng-resource to get data from my server and then place the data into a table grid like this:
<div ng-form name="grid">
<button type="submit" data-ng-disabled="grid.$pristine">Save</button>
<div class="no-margin">
<table width="100%" cellspacing="0" class="form table">
<thead class="table-header">
<tr>
<th>ID</th>
<th>Title</th>
</tr>
</thead>
<tbody class="grid">
<tr data-ng-repeat="row in grid.data">
<td>{{ row.contentId }}</td>
<td><input type="text" ng-model="row.title" /></td>
</tr>
</tbody>
</table>
</div>
</div>
Is there a way that I can make it so that clicking on the Submit button checks through the grid for the rows that changed and then calls a putEntity(row) function with the row as an argument?
You could do it a few ways, and remember every NgModelController has a $dirty flag which can use to check if the input has changed. But I would say the easiest way is just to do this:
Edit to HTML:
<input type="text" ng-model="row.title" ng-change="row.changed=true" />
<button ng-click="save()">Save</button>
In JS:
$scope.save = function () {
// iterate through the collection and call putEntity for changed rows
var data = $scope.grid.data;
for (var i = 0, len = data.length; i < len; i++) {
if (data[i].changed) {
putEntity(data[i]);
}
}
}
Here's something that could work. It is built with the JSFiddle from the first comment as a basis.
First, I changed the data-ng-disabled attribute to changes.length <= 0 and added $scope.changes = [] to the controller.
$scope.changes = [];
Then I added a watch on $scope.data
$scope.$watch('data', function(newVal, oldVal){
for(var i = 0; i < oldVal.length; i++){
if(!angular.equals(oldVal[i], newVal[i])){
console.log('changed: ' + oldVal[i].name + ' to ' + newVal[i].name);
var indexOfOld = $scope.indexOfExisting($scope.changes, 'contentId', newVal[i].contentId);
if(indexOfOld >= 0){
$scope.changes.splice(indexOfOld, 1);
}
$scope.changes.push(newVal[i]);
}
}
}, true); // true makes sure it's a deep watch on $scope.data
Basically this runs through the array and checks if anything has changed using angular.equals. If an object has changed it is checked if it exists in $scope.changes already. If it does, it's removed. After that newVal[i] is pushed to $scope.changes
The $scope.indexOfExisting is taken from this SO question
$scope.indexOfExisting = function (array, attr, value) {
for(var i = 0; i < array.length; i += 1) {
if(array[i][attr] === value) {
return i;
}
}
};
Finally I made the $scope.checkChange() look like so
$scope.checkChange = function(){
for(var i = 0; i < $scope.changes.length; i++){
console.log($scope.changes[i].name);
//putEntity($scope.changes[i])
}
$scope.changes = [];
};
This will then give you the ability to submit only the changed rows.
I decided to do this as follows:
Here is where I get the data and then make a copy of it:
getContents: function ($scope, entityType, action, subjectId, contentTypeId, contentStatusId) {
entityService.getContents(entityType, action, subjectId, contentTypeId, contentStatusId)
.then(function (result) {
$scope.grid.data = result;
$scope.grid.backup = angular.copy(result);
$scope.grid.newButtonEnabled = true;
}, function (result) {
alert("Error: No data returned");
$scope.grid.newButtonEnabled = false;
});
},
Then later when it comes to saving I use angular.equals to compare with a backup:
$scope.saveData = function () {
var data = $scope.grid.data;
for (var i = 0, len = $scope.grid.data.length; i < len; i++) {
if (!angular.equals($scope.grid.data[i], $scope.grid.backup[i])) {
var rowData = $scope.grid.data[i]
var idColumn = $scope.entityType.toLowerCase() + 'Id';
var entityId = rowData[idColumn];
entityService.putEntity($scope.entityType, entityId, $scope.grid.data[i])
.then(function (result) {
angular.copy(result, $scope.grid.data[i]);
angular.copy(result, $scope.grid.backup[i]);
}, function (result) {
alert("Error: " + result);
})
}
}
$scope.grid.newButtonEnabled = true;
$scope.grid.saveButtonEnabled = false;
$scope.$broadcast('tableDataSetPristine');
}
I did something quite similar for myself, and I used a different way, I decided to directly bind all the ng-models to the data, which let me work with the indexes if I need to check every row, but I could also decide to send the whole data to the server
Then, I just have to watch all the changes made to every index (even with big data, I just have to add/remove an integer) and store them in an array
Once finished, I can click the submit button, which will loop on every index I've touched, to check if the content is really different from the original one, and then I can do whatever I want with it (like calling a putEntity function, if I had one)
I made a fiddle based on your html code, it will be easier to play with it than with a copy/paste of the code here : http://jsfiddle.net/DotDotDot/nNwqr/1/
The main change in the HTML is this part, binding the model to the data and adding a change listener
<td><input type="text" ng-model="data[$index].title" ng-change="notifyChange($index)"/></td>
I think the javascript part is quite understandable, I log indexes while the data is modified, then, later, when I click on the submit button, it can call the right function on the modified rows only, based on the logged indexes