Using the pipe/ajax plugin example at http://lorenzofox3.github.io/smart-table-website I have been trying to implement an Angular.js smart table with a loading indicator whilst my ajax call is still loading.
angular-boostrap.js
var eposWebAngularStrutsApp = angular.module('eposWebAngularStrutsApp', ['ngResource','smart-table']);
angular-controller.js
eposWebAngularStrutsApp.controller('StoreHealthCheckController', ['$scope','StoreServerHealth', function ($scope, StoreServerHealth) {
//http://www.sitepoint.com/creating-crud-app-minutes-angulars-resource/
var ctrl = this;
this.displayed = [];
this.callServer = function callServer(tableState) {
ctrl.isLoading = true;
StoreServerHealth.query(function(result) {
ctrl.displayed = result.data;
ctrl.isLoading = false;
}); //query() returns all the entries
};
}]);
angular-service.js
eposWebAngularStrutsApp.factory('StoreServerHealth', function($resource) {
return $resource('json/storeHealthCheckList.action'); // Note the full endpoint address
});
My JSP...
<table class="table table-striped" st-pipe="mc.callServer" st-table="mc.displayed" ng-controller="StoreHealthCheckController">
<thead>
<tr>
<th>Store</th>
<th>Server</th>
<th>Conn Status</th>
<th>Last Updated</th>
<th>MDI</th>
<th>Last Synched (MDI)</th>
<th>DSM</th>
<th>Last Synched (DSM)</th>
<th>Trading Status</th>
<th>Build</th>
</tr>
</thead>
<tbody ng-show="!mc.isLoading">
<tr ng-repeat="row in mc.displayed">
<td>{{row.locationId}}</td>
<td>{{row.clientId}}</td>
<td>{{row.status}}</td>
<td>{{row.displayLastUpdateTime}}</td>
<td>{{row.replicationStatus}}</td>
<td>{{row.displayLastReplicationSyncTime}}</td>
<td>{{row.dsmReplicationStatus}}</td>
<td>{{row.dsmLastSynchTime}}</td>
<td>{{row.storeTradingStatus}}</td>
<td>{{row.buildVersion}}</td>
</tr>
</tbody>
<tbody ng-show="mc.isLoading">
<tr>
<td colspan="10" class="text-center">Loading ... </td>
</tr>
</tbody>
</table>
But I keep getting an error TypeError: href is null firebug/content/debugger/stackFrame/StackFrame.js.
Can someone let me know what I might be doing wrong here.
Thanks
The comment posted above was the answer to this question. I had forgotten to Alias the controller.
Related
I have something like this:
<table id="thatTable" class="table toggle-circle">
<thead>
<tr>
<th>ID</th>
<th>FieldA</th>
<th data-hide="all">FieldB</th>
<th data-hide="all">FieldC</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="4">
<div class="text-right">
<ul class="pagination"></ul>
</div>
</td>
</tr>
</tfoot>
</table>
Then a JS like this:
var fillThatTable = function (list) {
$.each(list, function (index, item) {
$('#thatTable tbody').append($('<tr>')
.append($('<td>').text(item.ID))
.append($('<td>').text(item.FieldA))
.append($('<td>').text(item.FieldB))
.append($('<td>').text(item.FieldC))
)
);
});
};
Everything works fine, the table gets the data and shows it all. Problem comes when I want to set footable() to that table, like so:
$(document).ready(function () {
fillThatTable();
$('#thatTable').footable();
});
And instead of getting something beautiful, I just receive an average filtered table, almost like I didn't put that $('#thatTable').footable(). I checked the JS are imported, they are. Is it maybe because the table doesn't have anything in the tbody? What am I missing?
Dream:
Reality:
I've updated PM's fiddle to make an easier use of FooTable: http://jsfiddle.net/0pb4x7h6/1
If your html changes to this:
<table id="thatTable" class="table toggle-circle">
<thead>
<tr>
<th data-name="ID">ID</th>
<th data-name="FieldA">FieldA</th>
<th data-name="FieldB" data-breakpoints="all">FieldB</th>
<th data-name="FieldC" data-breakpoints="all">FieldC</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="4">
<div class="text-right">
<ul class="pagination"></ul>
</div>
</td>
</tr>
</tfoot>
</table>
Then you can simplify your script to this:
$(document).ready(function () {
var list = [
{"ID":"1","FieldA":"A1","FieldB":"B1","FieldC":"C1"},
{"ID":"2","FieldA":"A2","FieldB":"B2","FieldC":"C2"},
{"ID":"3","FieldA":"A3","FieldB":"B3","FieldC":"C3"}
];
// No need for this
//fillThatTable();
$('#thatTable').footable({
rows: list
});
});
I'm working on an app where I need a calendar skeleton (without the standard events) so I can put tables inside each cell, so I'm using the Angular Bootstrap Calendar with custom cell templates. I have everything working fine in terms of displaying the custom template in each cell and being able to navigate between months, but I need to be able to access each individual day and make data available in each one.
Here's my controller:
(function() {
angular.module('myApp')
.controller('calendarController', function($scope, $state, moment, calendarConfig) {
var vm = this;
calendarConfig.templates.calendarMonthCell = 'views/calendar/dayTemplate.html';
calendarConfig.dateFormatter = 'moment';
vm.events = [];
vm.calendarView = 'month';
vm.viewDate = moment().startOf('month').toDate();
$scope.$on('$destroy', function() {
calendarConfig.templates.calendarMonthCell = 'mwl/calendarMonthCell.html';
});
});
})();
and the corresponding dayTemplate.html:
<div class="cal-month-day">
<span
class="pull-right"
data-cal-date
ng-click="calendarCtrl.dateClicked(day.date)"
ng-bind="day.label">
</span>
<!--
<small style="position: absolute; bottom: 10px; left: 5px">
There are {{ day.events.length }} events on this day
</small> -->
<!-- <table class="table table-bordered table-condensed"> -->
<table class="table table-bordered table-condensed">
<thead>
<tr>
<td>Station</td>
<td>Position</td>
<td>Name</td>
</tr>
</thead>
<tbody>
<tr>
<td rowspan="3" align="top">1</td>
<td>Position</td>
<td>Name</td>
</tr>
<tr>
<td>Position</td>
<td>Name</td>
</tr>
<tr>
<td>Position</td>
<td>Name</td>
</tr>
</tbody>
</table>
<table class="table table-bordered table-condensed">
<tbody>
<tr>
<td rowspan="3" align="top">2</td>
<td>Position</td>
<td>Name</td>
</tr>
<tr>
<td>Position</td>
<td>Name</td>
</tr>
<tr>
<td>Position</td>
<td>Name</td>
</tr>
</tbody>
</table>
<table class="table table-bordered table-condensed">
<tbody>
<tr>
<td rowspan="3" align="top">3</td>
<td>Position</td>
<td>Name</td>
</tr>
<tr>
<td>Position</td>
<td>Name</td>
</tr>
<tr>
<td>Position</td>
<td>Name</td>
</tr>
</tbody>
</table>
</div>
When using the calendar as it normally is used, you can see that the days.events object has the data, but I need to access that object, or create my own so I can fill my tables. Is there a simple (or even not so simple) way to do that?
Thanks.
UPDATE: I just went back and read the docs and noticed this
An optional expression that is evaluated on each cell generated for
the year and month views. calendarCell can be used in the expression
and is an object containing the current cell data which you can modify
(see the calendarHelper service source code or just console.log it to
see what data is available). If you add the cssClass property it will
be applied to the cell.
Due to my lack of knowledge, I'm not understanding how to use this to override. If I console.log calendarCell in my calendarController it chokes because that object doesn't exist. If I'm reading this correctly, I can intercept the cell data and modify, but I'm not understanding how.
In this case, RTFM turned out to be the correct answer. Per the docs:
<div ng-controller="CellModifierCtrl as vm">
<ng-include src="'calendarControls.html'"></ng-include>
<mwl-calendar
events="vm.events"
view="vm.calendarView"
view-date="vm.viewDate"
cell-modifier="vm.cellModifier(calendarCell)">
</mwl-calendar>
</div>
goes with this in the controller:
vm.cellModifier = function(cell) {
console.log(cell);
if (cell.label % 2 === 1 && cell.inMonth) {
cell.cssClass = 'odd-cell';
}
cell.label = '-' + cell.label + '-';
};
and voila!, you have access to the data. I'm still trying to figure out how to pass additional data into the function, but I'll open a separate question for that.
I'm quite new to AngularJS and I'm facing some problems showing objects from an array in my view.
I have the following javascript code:
// list initialization:
vm.latestInvoices = { invoices: []};
....
// adding function to viewmodel:
vm.getLatestInvoices = getLatestInvoices;
...
function getLatestInvoices() {
console.log("Test 1234");
var servicename = "GetLatestInvoicesRequest";
var params = {};
httpCall(servicename, params).then(function (data) {
vm.latestInvoices = data;
console.log(data);
return vm.latestInvoices;
})["catch"](function (data) {
console.log("getLatestInvoices error");
});
}
My HTML view:
<div class="col-lg-12">
<p id="overview-headline">Invoices Overview</p>
<div class="scrollCustomers" ng-init="vm.getLatestInvoices()">
<table class="table table-hover">
<thead>
<tr>
<th>Client</th>
<th>Project</th>
<th>ID</th>
<th>Inv. Date</th>
<th>Start Date</th>
<th>End Date</th>
<th>DKK ex VAT</th>
<th>CIG</th>
<th>Attention</th>
<th>Cust. Manager</th>
<th>Regarding</th>
<th>Due Date</th>
<th>Finalized</th>
<th>Paid</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="invoice in invoices">
<td>{{invoice.CompanyName}}</td>
<td>Project Name</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>Default</td>
<td></td>
<td></td>
<td></td>
<td>N/A</td>
<td>N/A</td>
<td>N/A</td>
</tr>
</tbody>
</table>
</div>
</div>
In the Google Dev console, the array and it's objects are returned fine. The view doesnt return the default values, Project Name, Default and N/A, so my guess is that for some reason, invoices in ng-repeat is never called?
Thanks in advance!
Attach the result to the $scope:
httpCall(servicename, params).then(function (data) {
vm.latestInvoices = data;
console.log(data);
$scope.invoices = data;
})["catch"](function (data) {
console.log("getLatestInvoices error");
});
}
I am binding data to a table using Knockout JS and the JQuery/Bootstrap based; Data Table API. The table becomes unresponsive sporadically when sorted or loaded. There are no errors in the log.
It also shows 0 of 0 data as illustrated in the screenshot below:
I have seen similar errors/issues but could not get a solutions for them, E.g. This post:
Code:
function viewModel(){
var self = this;
self.Data = ko.observableArray([]);
$.getJSON('https://restcountries.eu/rest/v1/all', function(data){
self.Data(data);
});
}
ko.applyBindings(viewModel());
$(document).ready(function() {
$('#example').dataTable();
});
HTML:
<div class="table-responsive">
<table id="example" cellspacing="0"
class="table table-striped table-bordered table-condensed">
<thead>
<tr>
<th scope="col">Country</th>
<th scope="col">Capital</th>
<th scope="col">Population</th>
<th scope="col">Region</th>
</tr>
</thead>
<tfoot>
<tr>
<th scope="col">Country</th>
<th scope="col">Capital</th>
<th scope="col">Population</th>
<th scope="col">Region</th>
</tr>
</tfoot>
<tbody data-bind="foreach: Data">
<tr>
<td data-bind="text: name"></td>
<td data-bind="text: capital"></td>
<td data-bind="text: population"></td>
<td data-bind="text: region"></td>
</tr>
</tbody>
</table>
</div>
Here is a full working example (JSFiddle) utilizing a REST API so that the exact problem is accurately replicated:
I think the problem with your example may be with how you're dealing with your data when you get it back from the API call.
I've put together a quick example that achieves what I think you're trying to achieve and the sorting and searching work quickly for me.
When I get the JSON data back from the API, I use the Knockout arrayMap utility function to create an array of "Country" objects that have observable properties that I have mapped the JSON data to. I've bound the table to my observableArray of Country objects.
Initialising the data table in the same way you have works fine for me in this case.
The full working solution is here: http://plnkr.co/edit/eroIox6zqBFOVnf86Mdk?p=preview
script.js
var ViewModel = function(jsonData) {
var countries = ko.utils.arrayMap(jsonData, function(item) {
return new Country(item)
});
this.Countries = ko.observableArray(countries);
};
var Country = function(jsonItem) {
this.Name = ko.observable(jsonItem.name);
this.Capital = ko.observable(jsonItem.capital);
this.Population = ko.observable(jsonItem.population);
this.Region = ko.observable(jsonItem.region);
};
window.onload = function() {
$.getJSON('https://restcountries.eu/rest/v1/all', function(data) {
ko.applyBindings(new ViewModel(data));
$("#example").dataTable();
});
}
index.html
<table id="example" cellspacing="0" class="table table-striped table-bordered table-condensed">
<thead>
<tr>
<th scope="col">Country</th>
<th scope="col">Capital</th>
<th scope="col">Population</th>
<th scope="col">Region</th>
</tr>
</thead>
<tfoot>
<tr>
<th scope="col">Country</th>
<th scope="col">Capital</th>
<th scope="col">Population</th>
<th scope="col">Region</th>
</tr>
</tfoot>
<tbody data-bind="foreach: Countries">
<tr>
<td data-bind="text: Name"></td>
<td data-bind="text: Capital"></td>
<td data-bind="text: Population"></td>
<td data-bind="text: Region"></td>
</tr>
</tbody>
</table>
Tables are fairly slow to render within Knockout, and if your table is based on a computed, I could see how you could have some issues with redrawing time. But that's not happening here.
Apart from loading the data and binding it to the table rows, there's no data manipulation going on in your viewmodel. All the data manipulation is done by the dataTable plug-in, which you initialize with a single jQuery call. Properly, that should be done within a binding handler. You also need to know what is going on within the plug-in when it sorts, filters, or whatever it does, because you may need to mediate those changes back to your observableArray within your binding handler.
Bottom line: you need a binding handler for the dataTable. There may be one already written; I haven't Googled for it. Give that a try.
I'm starting to learn some AngularJS and am trying to determine its practicality when working along side ASP.NET MVC.
Let's say I have a view which displays beers from a repository in a table. I could output the information in two ways.
1.Using MVC's Razor Engine
Here, the model containing the beers is processed on the server and the html page rendered.
<h3>Rendered using Razor!</h3>
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Colour</th>
<th>Tasted?</th>
</tr>
</thead>
<tbody>
#foreach (var beer in Model)
{
<tr>
<td>#beer.Name</td>
<td>#beer.Colour</td>
<td>#beer.Tried</td>
</tr>
}
</tbody>
</table>
2.Using Angular repeat
Here, the HTML is returned straight away and angular performs a AJAX call to the controller to retrieve its model. After it has that data it outputs it into the table.
<h3>Rendered using Angular!</h3>
<table class="table table-condensed table-striped">
<thead>
<tr>
<th>Name</th>
<th>Colour</th>
<th>Tasted?</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="beer in model">
<td>{{ beer.Name }}</td>
<td>{{ beer.Colour }}</td>
<td>{{ beer.Tried }}</td>
</tr>
</tbody>
</table>
Controller
angular.module('BeerController', [])
.controller('BeerCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.model = {};
$http.get('/Beer/GetBeers').success(function (data) {
$scope.model = data;
});
}]);
My Question
Is there a way to use the Razor engine for the initial load of the data and Angular for everything else (paging calls, searching etc.)? In other words, how do I bind existing html to a controllers model in AngularJS?
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Colour</th>
<th>Tasted?</th>
</tr>
</thead>
<tbody>
<tr>
<td>Fosters</td>
<td>Gold</td>
<td>True</td>
</tr>
<tr>
<td>Becks</td>
<td>Amber</td>
<td>False</td>
</tr>
<tr>
<td>Cobra</td>
<td>Gold</td>
<td>True</td>
</tr>
</tbody>
</table>
In your MVC Controller
public ActionResult Index()
{
var model =.....
//optional
JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() };
ViewBag.data = JsonConvert.SerializeObject(model, Formatting.Indented, jsonSerializerSettings);
return View()
}
In your view Index.cshtml
...
#section Scripts {
//make sure that all anular scripts are loaded before that
<script>
angular.module('BeerController').service('dataService', function () {
var data= #Html.Raw(ViewBag.data);
return {
data:data
}
});
...
</script>
}
Angular Part:
angular.module('BeerController', [])
.controller('BeerCtrl', ['$scope', '$http','dataService', function ($scope, $http,dataService) {
// now you can get data from your dataService without extra trip to your server
$scope.model = dataService.data
....
}]);