I'm having two tables witch renders data trough angularJs, coming from 2 c#-methods.
The tables are structured almost exactly the same. The first one below is used as I searchfield and the other one is used basiclly to render names.
My problem is that the first one works perfect, but the other one does not. And I don't see the problem. Any help would be appreciated. // Thanks!
Here are my two tables. (the first one is working)
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.18/angular.min.js"></script>
<div ng-app="searchApp">
<div ng-controller="searchController">
#*first table works*#
<span style="color: white">Search:</span> <input data-ng-click="myFunction()" ng-model="searchText">
<table style="color: white" id="searchTextResults">
<tr><th>Name</th></tr>
<tr ng-show="!!searchText.length != 0" ng-repeat="friend in friends | filter:searchText">
<td data-id="{{friend.id}}" data-ng-click="SendFriendRequest(friend.id)">{{friend.id.replace("RavenUsers/","")}}</td>
</tr>
</table>
#*Does not work*#
<input type="button" value="Get friends requests" data-ng-click="GetFriendRequests()">
<table style="color: white">
<tr><th>Friend requests</th></tr>
<tr ng-repeat="friendRequest in friendRequests">
<td data-id="{{friendRequest.UserWhoWantsToAddYou}}" data-ng-click="acceptUserRequest(friendRequest.UserWhoWantsToAddYou)">{{friendRequest.UserWhoWantsToAddYou}}</td>
</tr>
</table>
</div>
</div>
HERE IS MY SCRIPT
<script>
var App = angular.module('searchApp', []);
App.controller('searchController', function ($scope, $http) {
//Get all users to the seachFunction
$scope.myFunction = function () {
var result = $http.get("/Home/GetAllUsersExeptCurrentUser");
result.success(function (data) {
$scope.friends = data;
});
};
//Get friendRequests from other users
$scope.GetFriendRequests = function () {
var result = $http.get("/Home/GetFriendRequests");
result.success(function (data) {
$scope.friendRequests = data;
});
};
});
</script>
The first script-function called myFunction works perfect and the data coming from my c#-method looks like this:
[{"id":"RavenUsers/One"},{"id":"RavenUsers/Two"},{"id":"RavenUsers/Three"}]
The second script-function called GetFriendRequests does not work, and as far as I can see there is no difference between this data passed into here than the data passed into myFunction:
[{"userWhoWantsToAddYou":"RavenUsers/Ten"},{"userWhoWantsToAddYou":"RavenUsers/Eleven"}]
I'd suggest you use then instead of success because $http returns a promise.
If your table doesn't "render" then put a breakpoint inside success function, console.log() the data or check friendRequests inside your HTML template, e.g. using <div>{{ friendRequests | json }}</div>, to ensure you actually got data from response.
Now you do not handle exceptions at all.
Example:
result.then(function(data) {
console.log('got data')
},function(error) {
console.log('oh noes :( !');
});
Related plunker here http://plnkr.co/edit/KzY8A3
It would be helpful if you either (a) provided a plunker to your code or (b) provided the error message.
ng-repeat requires a uniquificator on each item in the repeat, which defaults to item.id. If you don't have an id field on the item, you'll need to tell angular what field to use.
https://docs.angularjs.org/api/ng/directive/ngRepeat
So I'd suggest changing
<tr ng-repeat="friendRequest in friendRequests">
to
<tr ng-repeat="friendRequest in friendRequests track by userWhoWantsToAddYou">
and see if that works.
Related
I have some complication with service removing. I have function that removes service on the server but I have to reload page to update table. I found way how to remove row by click-binding but there is the issue beacuse I can only remove row or get ID for delete service from server NOT both. :/
This is example of code that removes service on the server but doesn't remove table row.
HTML:
<table id="serviceView" class="fixed_header" border: 1>
<thead>
<tr>
<th>Name</th>
<th>Adress</th>
<th>Notification</th>
</tr>
</thead>
<tbody data-bind="foreach: services">
<tr>
<td data-bind="text: name"></td>
<td data-bind="text: address"></td>
<td data-bind="text: serviceId"></td>
<td ><button data-bind="click: $parent.DeleteService.bind(this, serviceId)">Remove</button></td>
</tr>
</tbody>
</table>
JS:
self.services = ko.observableArray([]);
self.lastCheck = ko.observable();
$.getJSON("http://localhost:55972/api/status", function (data) {
self.services(data.services);
self.lastCheck = data.lastCheck;
}); //////This is loading data to the table from server
self.DeleteService = function (serviceId) {
$.ajax({
type: "GET",
url: "http://localhost:55972/api/services/remove/" + serviceId,
}).done(function () {
self.services.remove(serviceId)
})
};
This is example of code that removes table row
When I use click-binding like this:
<button data-bind="click: $parent.DeleteService">Remove</button>
And change delete function to this:
self.DeleteService = function (serviceId) {
self.services.remove(serviceId)
$.ajax({
type: "GET",
url: "http://localhost:55972/api/services/remove/" + serviceId,
}).done(function () {
// here I want to remove row but i doesnt goes here without service ID.
})
};
It removes row but instead serviceId I got [object, object] in the URL.
Can you help me with it ? I got idea to use jquery to just update the table but it's seems unnecessarily complicated for me when I can use knockout.
I know the solution is not that hard but I'am just unable to solve it..... -_-
I'am sorry for taking time with this bullshit but this is my first real project and I'am so desperate at this point beacuse I have lot of things to do and I'am stucked on this.
In your Js code, you can try this:
self.services = ko.observableArray([]);
self.lastCheck = ko.observable();
$.getJSON("http://localhost:55972/api/status", function (data) {
self.services(data.services);
self.lastCheck = data.lastCheck;
}); //////This is loading data to the table from server
var serviceIdRemoved;
self.DeleteService = function (serviceId) {
serviceIdRemoved = serviceId; // now you can do whatever you need more with this value
$.ajax({
type: "GET",
url: "http://localhost:55972/api/services/remove/" + serviceId,
}).done(function () {
self.services.remove(serviceId)
})
};
With this way of work you can user the content of the variable and don´t loose it. Also if you get [Object, Object], you can:
console.log(serviceId) // to see the content in the console.
JSON.stringify(data) //to see the content in html
This source could help you to understand it better.
The [object, object] you are seeing is actually the data and event objects which are secretly added to the JS function parameters by Knockout. If you want to add your own parameter to the click binding then you should do it like this:
<button data-bind="click: function(data, event) { $parent.DeleteService(serviceId, data, event) }">Remove</button>
You can then define your JS function as follows:
self.DeleteService = function (serviceId, data, event) {
[code here...]
}
You can read up on the exact details of it in the excellent Knockout documentation here:
http://knockoutjs.com/documentation/click-binding.html
It's about half-way down under the heading that reads Note 2: Accessing the event object, or passing more parameters
I am developing my first angular-app with an .Net backend.
I get my data async from a webmethod using a http.post. That all works fine.
Client-side I would like to do some simple calculations (a final row in a table which contains sums of all the data in table)
The code to do this is pretty straight forward but my problem is the data i not ready when I try to do it.
I have read that I could use a promise and a service or a factory. But I am not sure what we be the best way to go.
My code for the view:
<div ng-controller="taskCtrl as ctrl">
<div class="col-md-10 container outer">
<h1 class="center-block">{{ctrl.SprintViewModel.SprintName}}</h1>
<table id="SprintMetaDate">
<tr><td>Projekt:</td><td>{{ctrl.SprintViewModel.ProjektName}}</td></tr>
<tr><td>Periode:</td><td>{{ctrl.SprintViewModel.StartDate}} - {{Ctrl.SprintViewModel.EndDate}}</td></tr>
<tr><td>Udarbejdet af/d:</td><td>{{ctrl.SprintViewModel.MadeBy}}</td></tr>
</table>
<h3>Sprint Resume:</h3>
<br/>
{{ctrl.SprintViewModel.SprintResume}}
<h3>Sprint afslutning:</h3>
{{ctrl.SprintViewModel.SprintDemo}}
<h2>Scope og Økonomi </h2>
<h3>Sprint Opgaver</h3>
<table id="SprintTasks" class="col-md-12">
<tr><th>Opgave</th><th>Estimat</th><th>Forbrug</th><th>Udest.</th><th>*</th><th>Pris (DKK)</th></tr>
<tr ng-repeat="x in ctrl.SprintViewModel.Tasks">
<td style="width: 40%">{{ x.Description }}</td>
<td>{{ x.TimeEst }}</td>
<td>{{ x.TimeUsed }}</td>
<td>{{ x.TimeRemaining }}</td>
<td>{{ ctrl.CalcPrecisionOfEstimat(x.TimeUsed,x.TimeRemaining,x.TimeEst) | number:2}} %</td>
<td>{{x.Price}}</td>
</tr>
<tr>
<td>Ialt</td>
<td>{{ ctrl.TotalEstimat() }}</td>
<td>{{ ctrl.TotalTimeUsed() }}</td>
<td>{{ctrl.TotalTimeRemaining()}}</td>
<td>{{ctrl.TotalPrecision()}}</td>
<td>{{ctrl.TotalPrice()}}</td>
</tr>
</table>
* Forbrug + Udestående i forhold til estimat
<br/>
Udestående opgaver er planlagt ind i næstkommende sprint.
</div>
</div>
</form>
<script>
var app = angular.module('myApp', []);
app.controller('taskCtrl', function($scope, $http) {
var ctrl = this;
ctrl.SprintViewModel = null;
ctrl.TotalEstimat=function() {
var totalEstimat=0;
for (i=0; i<ctrl.SprintViewModel.Tasks.count;i++) {
totalEstimat += ctrl.SprintViewModel.Tasks[i].Estimate;
}
return totalEstimat;
}
ctrl.TotalPrecision = function () {
var totalPrecision=0;
angular.forEach(ctrl.SprintViewModel.Tasks, function (value, key) {
totalPrecision += Number(value);
});
$http.post('SprintRapport.aspx/GetSprintViewModel', {})
.then(function(response, status, headers, config) {
console.log("I success");
ctrl.SprintViewModel = response.data.d;
});
});`
As already mentioned I get a nullreference every when the page-load on all the methods in the last row, because ctrl.SprintviewModel is undefined. I have only included one of the methods for simplicity, the problem is the same for all of them.
So my question is how do I make sure that ctrl.TotalEstimat() first get called then ctrl.SprintViewModel is assigned?
You can add ng-if condition to the last <tr> which resolves to true when data is ready to populate in your controller. So you can define $scope.loading = false initially and once your code is ready to populate you set $scope.loading=true and that will call $digest cycle internally and your view gets updated.
There are several things that you could do. I've fixed this kind of issue by placing guard conditions in the functions. These check that the necessary variables have been set before continuing. So adding if (!ctrl.SprintViewModel) return; at the beginning of the function as follows:
ctrl.TotalEstimat=function() {
// Guard Condition to prevent function executing in invalid state.
if (!ctrl.SprintViewModel) return;
var totalEstimat=0;
for (i=0; i<ctrl.SprintViewModel.Tasks.count;i++) {
totalEstimat += ctrl.SprintViewModel.Tasks[i].Estimate;
}
return totalEstimat;
}
It's another option, but as you have already alluded to, I think that promises and the $q library is the proper angular way to fix this sort of thing.
This is my controller function to get data from server.
function carsController($http, $scope, $timeout) {
var vm = this;
vm.getCarData = getCarData;
function getCarData(){
$http.get('/api/getData').then(function (response) {
console.log(response.data.message);
vm.list = response.data.message;
});
}
}
Here is the data returned.
{
"message":[
{
"emp_id":1,
"emp_name":"toyota",
"city":"city1",
"nic_no":4554
},
{
"emp_id":2,
"emp_name":"sunny",
"city":"city2",
"nic_no":57412
},
{
"emp_id":3,
"emp_name":"tata",
"city":"city3",
"nic_no":1234
}
]
}
and html code to show data. I am using carsController as cars
<div class="row" data-ng-init="cars.getCarData()">
<div class="panel panel-default">
<table class="table table-bordered table-hover">
<tr>
<th>Name</th>
<th>Pages</th>
</tr>
<tr ng:repeat="vehicle in cars.list track by $index">
<td>{{vehicle.emp_name}}</td>
<td>{{vehicle.city}}</td>
</tr>
</table>
</div>
</div>
instead of showing data, UI show 100+ empty rows when page loaded.
What could be the issue?
UPDATED
If I manually set value as below, This works well.
vm.list = [
{
"emp_id":1,
"emp_name":"toyota",
"city":"city1",
"nic_no":4554
},
{
"emp_id":2,
"emp_name":"sunny",
"city":"city2",
"nic_no":57412
},
{
"emp_id":3,
"emp_name":"tata",
"city":"city3",
"nic_no":1234
}
];
the issue is, as you can see in the console log you have posted, response.data.message is an object. Not an array.
Try this instead
vm.list = response.data.message.message;
The following will bind the message array
You have two problems.
You are assigning vm.list to response.data.message, which, as NJ_93 points out, is an object. Use
vm.list = response.data.message.message;
You're not calling your getCarData() function from your controller. So the data is never fetched.
Are you sure that the problem is not because of you have used two different objects. vm.list for receiving the data from $http and using cars.list for ng-repeat
store data to $scope.vm.list
and in the UI use ng-repeat="cars in vm.list track by $index"
What I'm trying to make is an angular app that reads in a json file and displays them, and allows users to edit the json file using html controls. Then, the user can create a new json object based on their selections and display it.
Here is a picture to help describe what I'm trying to do:
So, the user sees this, they make certain selections, e.g. lock them or delete them, then they hit create, and a new json file is returned based on which objects they have chosen to lock or delete.
At the moment I just have a standard angular app which gets and displays the json:
var app = angular.module('myApp', []);
app.controller('customersCtrl', function($scope, $http) {
$http.get("http://www.w3schools.com/angular/customers.php").then(function (response) {
$scope.myData = response.data.records;
});
$scope.createJson = function(){
// Create new json file
};
});
The body of my html/my angular app looks like this at the moment:
<div ng-app="myApp" ng-controller="customersCtrl">
<table>
<tr ng-repeat="x in myData">
<td>{{ x.Name }}</td>
<td>{{ x.City }}</td>
<td>{{ x.Country }}</td>
<td><input type="checkbox" name="lock" value="{{x.Name}}"></td>
<td><input type="checkbox" name="delete" value="{{x.Name}}"></td>
</tr>
</table>
<button ng-click="createJson()">Create</button>
</div>
Baiscally, I'm not sure if my approach is correct at the moment, and if it is, I don't really know what my next step is.
P.S. this is just test data I am using for the sake of learning/testing, it is not my data, I got it from: http://www.w3schools.com/angular/customers.php
You can try
JSON.stringify($scope.myData)
or
angular.toJson($scope.myData)
this will give you string representation of your data object. The rest is up to you, you may assign it to textarea, post it back to server (in this case, you most likely won't even need to encode it before) etc.
You should use
<td><input type="checkbox" name="lock" value="{{x.Name}}"></td>
<td><input type="checkbox" name="delete" value="{{x.Name}}"></td>
as
<td><input type="checkbox" name="lock" ng-model="x.Name"></td>
<td><input type="checkbox" name="delete" ng-model="x.Name"></td>
(Actually I didn't understand why you use string in checkbox. It should be boolean value).
By this way any change will change your $scope.myData.
On create you should take info from user and create a new JsonObject like
var newObject = {
Name: 'Name Surname',
City: 'City',
Country: 'Country'
}
And add this to your myData with;
$scope.myData.push(newObject);
I ended up creating an appropriate solution by simply creating a new and empty JSON object:
var newJson = [];
and populating it by looping through my original one and using array.push() to add the selected entries:
for (var person in $scope.myData){
if($scope.myData[person].Delete === false || $scope.myData[person].Lock === true){
newJson.push($scope.myData[person])
}
}
I am working with AngularJS. I am getting strange behavior from ng-repeat. I have a controller which returns me the data to ng-repeat such as:
.....
//My other JS Functions
.....
var app = angular.module('main', ['ngTable']).
controller('DemoCtrl', function($scope, ngTableParams) {
var data = [
//data in JSON form
];
$scope.tableParams = new ngTableParams({
page: 1, // show first page
count: 5 // count per page
}, {
total:data.length,
getData: function($defer, params) {
var slicedData = data.slice((params.page() - 1) * params.count(), params.page() * params.count());
alert(slicedData.length);
console.log(slicedData);
$defer.resolve(slicedData);
}
});
})
So, now one thing to note here that I am getting expected data after slicing it that I am passing to:
$defer.resolve(slicedData);
So, no issue seems here as it passes desired data.
Now, I have ng-repeat where I show data in form of tables such as:
<table ng-table="tableParams" class="table ng-table-responsive">
<tr ng-repeat="d in $data">
<td data-title="Name">
{{d.id}}
</td>
<td data-title="length">{{$data.length}}</td>
<td data-title="Age">
{{d.ciscoID}}
</td>
</tr>
</table>
So, here I am getting accurate length that is 5. But the number of records(rows) shown are 25(5*5) that each row is shown five times. Similarly, if I set the count to 10, then each record will be shown ten times.
I am unable to understand this scenario as
<td data-title="length">{{$data.length}}</td>
gives me the correct length then it should iterate correctly too.
P.S. My getData() method in the controller is called twice don't know why?
Any help/guidance regarding this will be highly appreciated. Thanks :-)
This Issue was fixed just by replacing the 'JS' and 'CSS' files with the latest ones.