I am using laravel 5.2 framework. I have successfully implemented datatables. By application design requirement, how to implement tables within the datatable cell?
Its not really directly possible unless you define your own table and style it with css as follows
styes for my inner table defined on my view
<style type="text/css">
h3 {
color: steelblue;
}
.subtabletable {
display: table;
width: 100%;
}
.subtable .row {
display: table-row;
}
.subtable .header {
font-weight: bold;
}
.subtable .cell {
display: table-cell;
padding: 5px;
}
</style>
Definition of my table in Html
<table id="example" class="display responsive nowrap" cellspacing="0" width="100%">
My javascript
$(document).ready(function () {
var request = $.ajax({
url: "sort_respones",
type: "GET",
dataType: "html"
});
request.done(function(msg){
dynamicdatatable(msg);
});
});
function dynamicdatatable(mydata){
var myData=JSON.parse(mydata) ;
console.log(myData);
var myColumns = [
{
title : "Employee",
data : "question"
},
{
title : "Type",
data : "response_type"
},
{
title : "Responses",
data : null,
render : function (data, type, row, meta) {
var subtableHtml = "<div class='subtable'>";
subtableHtml += "<div class='row header'><span class='cell'>Response</span><span class='cell'>Occurances</span></div>";
for (var i = 0; i < data.projects.length; i++) {
subtableHtml += "<div class='row'>";
subtableHtml += "<span class='cell'>" + data.projects[i].project + "</span>";
subtableHtml += "<span class='cell'>" + data.projects[i].role + "</span>";
subtableHtml += "</div>";
};
subtableHtml += "</div>";
return subtableHtml;
}
}
];
$('#example').dataTable({
searching: false,
paging: false,
data : myData,
columns : myColumns,
dom: 'Bfrtip',
buttons: [
'copyHtml5',
'excelHtml5',
'csvHtml5',
'pdfHtml5'
]
});
}
My controller function
function sort_respones(Request $request){
$results = DB::select( DB::raw("SELECT
questions.id,
questions.question,
questions.client_id,
surveys_session_answer_transactions.created_at,
surveys_session_answer_transactions.answer_text,
surveys_session_answer_transactions.answer_id,
surveys_session_answer_transactions.question_text,
questions.response_type_id,
Count(surveys_session_answer_transactions.answer_id) AS Occurances,
checkresponses.response,
radioresponses.response,
rating_bar_responses.maximum_value,
response_types.response_type
FROM
questions
INNER JOIN surveys_session_answer_transactions ON surveys_session_answer_transactions.question_id = questions.id
LEFT OUTER JOIN checkresponses ON checkresponses.question_id = surveys_session_answer_transactions.question_id AND checkresponses.id = surveys_session_answer_transactions.answer_id
LEFT OUTER JOIN rating_bar_responses ON rating_bar_responses.question_id = surveys_session_answer_transactions.question_id
LEFT OUTER JOIN radioresponses ON radioresponses.question_id = surveys_session_answer_transactions.question_id AND radioresponses.id = surveys_session_answer_transactions.answer_id
INNER JOIN response_types ON surveys_session_answer_transactions.response_type_id = response_types.type_id
where questions.client_id=:somevariable
GROUP BY
surveys_session_answer_transactions.question_id,
surveys_session_answer_transactions.answer_id"), array(
'somevariable' => "2",
));
//echo '<pre>'.print_r($results,1) .'</pre>';
// echo '<pre>';
// var_dump($results);
// echo '</pre>';
$new_question=0;
$dataUsage=[];
$final_array=[];
$responses=[];
$old_response="";$old_response_type="";
foreach ($results as $key) {
# code...
if ($new_question!=$key->id) {
# code...
if (isset($dataUsage[0])) {
# code...
array_push($final_array, array('question' =>$old_response,'response_type'=>$old_response_type,'projects' => ($responses)));
$responses=[];
//array_push($final_array, $dataUsage);
$dataUsage=[];
$responses_string="<table>";
}
array_push($dataUsage, array('question' => $key->question,'response_type'=>$key->response_type ));
$old_response=$key->question;
$old_response_type=$key->response_type;
// $responses_string='<TR><TD>'.$key->answer_text.'</TD><TD>: '.$key->Occurances.'<br></TD></TR>';
array_push($responses,array('project' => $key->answer_text, 'role' => $key->Occurances ));
}else{
// $responses_string=$responses_string.'<TR><TD>'.$key->answer_text.'</TD><TD> :'.$key->Occurances.'<br></TD></TR>';
array_push($responses,array('project' => $key->answer_text, 'role' => $key->Occurances ));
}
$new_question=$key->id;
}
array_push($final_array, array('question' =>$old_response,'response_type'=>$old_response_type,'projects' => ($responses)));
// echo '<pre>';
// var_dump($final_array);
// echo '</pre>';
// echo json_encode( array('data' =>$final_array ));
// $myData = array( array('employee' =>'Bob Smith', 'projects'=> array(array('project'=>'Alpha', 'role'=>'leader' ), array('project'=>'Alpha1', 'role'=>'leader1' ),array('project'=>'Alpha', 'role'=>'leader' ))));
echo json_encode($final_array);
}
of course don't forget the necessary routes
Related
I have a daterange picker and it is fully working. However, I have a new target which is daterange with timepicker. But the thing is I don't know how to implement it like what I did on my daterange without timepicker. Is there any way where I can implement it? I have provided my codes below of my fully working daterange picker. I have provided also my screenshot of my current daterange and my target daterange with timepicker. Thank you in advance.
HTML:
<div class="img-fluid">
<div class="input-group">
From:
<input type="date" class="mr-4" id="from" name="from">
To:
<input type="date" id="to" name="to" style="margin-right:50px;">
</div>
</div>
<div class="tab-pane fade show active" id="custom-tabs-two-1" role="tabpanel" aria-labelledby="custom-tabs-two-1-tab">
<table id="testing" class="table-striped table table-head-fixed" style="min-width:1000px; width:100%;">
<thead class="" style="background-color: #404040; color: white;">
<tr>
<th scope="col"><i class="fas fa-list-ol mr-2"></i>Transaction ID</th>
<th scope="col"><i class="fas fa-list-ol mr-2"></i>Reference No.</th>
<th scope="col"><i class="far fa-calendar-alt mr-2"></i>Date Requested</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
Script & Ajax:
var save_method; //for save method string
var table;
var base_url = '<?php echo base_url();?>';
$(document).ready(function() {
//datatables
var table = $('#testing').DataTable({
dom: 'lBfrtip',
buttons: [
'print', 'csv', 'copy', 'excel', 'pdfHtml5'
],
"processing": false, //Feature control the processing indicator.
"serverSide": true, //Feature control DataTables' server-side processing mode.
"order": [], //Initial no order.
// Load data for the table's content from an Ajax source
"ajax": {
"url": "<?php echo site_url('controller/ajax_list')?>",
"type": "POST",
"data": function ( data ) {
data.from = $('#from').val();
data.to = $('#to').val();
},
},
//Set column definition initialization properties.
"columnDefs": [
{
"targets": [ 0 ], //first column
"orderable": false, //set not orderable
},
{
"targets": [ -1 ], //last column
"orderable": false, //set not orderable
},
],
});
setInterval( function () {
testing.ajax.reload(null,false);
}, 1000);
Controller:
public function ajax_list()
{
$list = $this->repo->admin();
$data = array();
$no = $_POST['start'];
foreach ($list as $person) {
$no++;
$row = array();
$row[] = $person->transID;
$row[] = $person->refNumber;
$row[] = $person->dateRequested;
$data[] = $row;
}
$output = array(
"draw" => $_POST['draw'],
"recordsTotal" => $this->repo->showing_pending(),
"recordsFiltered" => $this->repo->count_filtered(),
"data" => $data,
);
//output to json format
echo json_encode($output);
}
}
Model:
var $table = 'ca';
var $column_order = array(null,'transID','dateRequested','refNumber');
var $order = array('transID' => 'desc');
var $column_search = array('transID','dateRequested','refNumber');
//set column field database for datatable orderable //set column field database for datatable searchable just firstname , lastname , address are searchable var $order = array('id' => 'desc'); // default order
private function _get_datatables_query()
{
if($this->input->post('from')){
$this->db->where('dateCre >=', $this->input->post('from'));
$this->db->where('dateCre <=', $this->input->post('to'));
}
$this->db->from('ca');
$i = 0;
foreach ($this->column_search as $item)
{
if($_POST['search']['value'])
{
if($i===0) // first loop
{
$this->db->group_start();
$this->db->like($item, $_POST['search']['value']);
}
else
{
$this->db->or_like($item, $_POST['search']['value']);
}
if(count($this->column_search) - 1 == $i)
$this->db->group_end();
}
$i++;
}
if(isset($_POST['order']))
{
$this->db->order_by($this->column_order[$_POST['order']['0']['column']], $_POST['order']['0']['dir']);
}
else if(isset($this->order))
{
$order = $this->order;
$this->db->order_by(key($order), $order[key($order)]);
}
}
function admin()
{
$this->_get_datatables_query();
if($_POST['length'] != -1)
$this->db->limit($_POST['length'], $_POST['start']);
$query = $this->db->get();
return $query->result();
}
public function showing_pending()
{
$this->db->from($this->table);
return $this->db->count_all_results();
}
function count_filtered()
{
$this->_get_datatables_query();
$query = $this->db->get();
return $query->num_rows();
}
}
What is your exact error? I think that you need to sanitize your post values before the query.
Change This:
$this->db->where('dateCre >=', $this->input->post('from'));
To this (please select the correct format in your case)
$from_date = DateTime::createFromFormat('d/m/Y h:m:s', $this->input->post('from'));
$this->db->where('dateCre >=', $from_date->format('Y-m-d h:m:s'));
Do it also with the "post('to')" value.
I want to show a data controller to view using ajax and I have already shown a data controller to view on the chart bar without ajax I need to get data on the chart bar using ajax but I don't have an idea how to show data on chart bar using ajax.
I don't have that good experience in JSON/AJAX/Laravel, I'm a beginner.
Controller
public function index()
{
$manager_hourlog = Hourlog::with('project', "user")->get()-
>groupBy('project.name');
$projects = [];
$totals = [];
foreach ($manager_hourlog as $key => $val) {
$projects[] = $key;
}
foreach ($manager_hourlog as $key2 => $val) {
$minutes = $val->sum('hour_work');
$totals[] = round($minutes / 60, 1);
}
$users = User::where("status", 1)->get();
$data = [
// manager report
'manager_projects' => $projects,
'totals' => $totals,
"manager_hourlog" => $manager_hourlog,
"auth" => $auth,
];
return response()->json(['data' => $data]);
return view('cms.dashboard', $data);
}
Script
<script>
// Employee report script
var colors = ["#1abc9c", "#2ecc71", "#3498db",
"#9b59b6", "#34495e", "#16a085", "#27ae60"];
#if ($auth->user_type != 1)
// manager report script
var managerchartbar = {
labels: {!! json_encode($manager_projects) !!},
datasets: [
#foreach($users as $user)
{
label: {!! json_encode($user->name) !!},
backgroundColor: colors[Math.floor(Math.random() * colors.length)],
// data: [300,200,500,700]
data: [
#foreach($manager_hourlog as $hourlog)
{{$hourlog->where("user_id", $user->id)->sum("hour_work") / 60}},
#endforeach
]
},
#endforeach
]
};
var ctx = document.getElementById('manager').getContext('2d');
window.myBar = new Chart(ctx, {
type: 'bar',
data: managerchartbar,
options: {
title: {
display: true,
text: 'Employees Report chart'
},
tooltips: {
mode: 'index',
intersect: false
},
responsive: true,
scales: {
xAxes: [{
stacked: true,
}],
yAxes: [{
stacked: true
}]
}
}
});
#endif
ajax
$.ajax({
type: 'GET',
url: '{{url("/dashboard")}}',
data: {
data: data
},
success: function(data){
console.log(data.data);
},
error: function(xhr){
console.log(xhr.responseText);
}
});
</script>
Html VIew
<div class="col-md-12">
<div class="card-box">
<div class="container-fluid">
<canvas id="manager" height="100">
</canvas>
</div>
</br>
</div>
</div>
Route
Route::get('/dashboard',
'DashboardController#index')->name('dashboard');
Can someone can help me? I get an error when I try to use a chart.
Undefined variable: label (View: C:\xampp\htdocs\latihan_penjualan\resources\views\home.blade.php)
in 15bd1eeee4b4d1b903b52322d785ce7ce1ab31d2.php line 31
This is my controller:
public function index()
{
$kategori = DB::table('kategoris')->get();
$data = [];
$label = [];
foreach ($kategori as $i => $v) {
$value[$i] = DB::table('produks')->where('id_kategori',$v->id)->count();
$label[$i] = $v->nama;
}
return view('home');
$this->with('value',json_encode($value));
$this->with('label',json_encode($label));
}
And this is my view:
<div id="container" style="width: 100%;">
<canvas id="canvas"></canvas>
</div>
<script type="text/javascript" src="http://www.chartjs.org/dist/2.7.2/Chart.bundle.js"></script>
<script type="text/javascript" src="http://www.chartjs.org/samples/latest/utils.js"></script>
<script type="text/javascript">
var color = Chart.helpers.color;
var barChartData = {labels: {!! $label !!},
datasets: [{
label: 'Produk Per Kategori',
backgroundColor: color(window.chartColors.red).alpha(0.5).rgbString(),
borderColor: window.chartColors.red,
borderWidth: 1,
data: {!! $value !!},
}],
};
window.onload = function() {
var ctx = document.getElementById('canvas').getContext('2d');
window.myBar = new Chart(ctx, {
type: 'bar',
data: barChartData,
options: {
responsive: true,
legend: {
position: 'top',
},
title: {
display: true,
text: 'Grafik Data Produk'
}
}
});
};
</script>
I already declared the variable $label.
Thanks in advance.
return view('home')
->with(['value'=>json_encode($value),'label'=>json_encode($label)]);
Fix this part after return view('home');
public function index()
{
$kategori = DB::table('kategoris')->get();
$data = [];
$label = [];
foreach ($kategori as $i => $v) {
$value[$i] = DB::table('produks')->where('id_kategori',$v->id)->count();
$label[$i] = $v->nama;
}
return view('home')->with('value',json_encode($value))->with('label',json_encode($label));
}
I want to change my button pdf from buttons datatable for my pdf from server, but in the same position how can I do it? my url from html2pdf http://localhost/store_websocket/inventory/pdf and I want to change the button from pdfmaker from datatable in the position for my url for html2pdf because I want researching datatables fails with 1k or more rows then I decide server side procesing
controller
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class PDF extends MY_Controller {
public function __construct(){
parent::__construct();
}
public function index(){
require_once(APPPATH.'third_party/html2pdf/vendor/autoload.php');
$data['products'] = $this->products->datatable();
//print_r($data);
$template_pdf = $this->load->view('view_pdf', $data, TRUE);
$html2pdf = new HTML2PDF('P', 'A4', 'en');
$html2pdf->WriteHTML($template_pdf);
$html2pdf->Output('exemple.pdf');
}
}
view
<style type="text/css">
P {text-align:justify;font-size: 12pt;}
li {text-align:justify;font-size: 12pt;}
table.page_footer {width: 100%; border: none; border-top: solid 1px #000000; }
table.products {border-collapse: collapse; width: 100%;}
table.products th,td {text-align: left; padding: 8px;}
table.products thead tr{font-size: 9.5pt}
table.products th {background-color: #34495e; color: white;}
tbody tr {background-color: #f2f2f2;}
</style>
<page backtop="14mm" backbottom="14mm" backleft="10mm" backright="10mm" style="font-size: 12pt">
<page_footer>
<table class="page_footer">
<tr>
<td style="width: 100%; text-align: right">
page [[page_cu]]/[[page_nb]]
</td>
</tr>
</table>
</page_footer>
<div style="width:100%;text-align:center;">
<h1><b>List Inventory</b></h1>
</div>
<table class="products">
<thead>
<tr>
<th>Codigo</th>
<th>Descripcion</th>
<th>Precio compra</th>
<th>Precio venta</th>
<th>Precio mayoreo</th>
<th>Existencia</th>
</tr>
</thead>
<tbody>
<?php foreach ($products as $key): ?>
<tr>
<td><?php echo $key['id']?></td>
<td><?php echo $key['descripcion']?></td>
<td><?php echo $key['precio_compra']?></td>
<td><?php echo $key['precio_venta']?></td>
<td><?php echo $key['precio_mayoreo']?></td>
<td><?php echo $key['existencia']?></td>
</tr>
<?php endforeach ?>
</tbody>
</table>
</page>
AJAX
$(function(){
URL_GET_DATATABLE = BASE_URL+'inventory/product/datatable';
URL_GET_VIEW_PRODUCT = BASE_URL+'inventory/product/getViewProduct';
URL_GET_ADD_PRODUCT = BASE_URL+'inventory/product/addProduct';
var table = $('#example').DataTable({
"lengthChange": false,
responsive: true,
dom: 'Blfrtip',
buttons: [{
extend: 'excelHtml5',
exportOptions:{
columns: [1,2,3,4,5,6]
}
},{
extend: 'csvHtml5',
exportOptions:{
columns: [1,2,3,4,5,6]
}
},{
extend: 'pdf',
exportOptions: {
columns: [1,2,3,4,5,6]
}
}],
ajax: {
url: URL_GET_DATATABLE,
type: 'POST',
},
columnDefs:[{
targets: -1,
data: null,
defaultContent: "<a href='#'><span class='glyphicon glyphicon-pencil'></span></a>"
},{
targets: 6,
render: function (data) {
return (data == 1) ? "<span class='label label-success'>active</span>":"<span class='label label-danger'>inactive</span>";
}
}],
fnRowCallback: function (data,nRow) {
if (nRow[6] == 0) {
$(data).css({'background-color':'#f2dede'})
}else if(nRow[6] == 1){
$(data).css({'background-color':'#dff0d8'})
}else{
}
}
});
$('#example tbody').on('click','a', function(e){
alert('thing');
});
$('#add').on('click',function(){
$("#description").mask("(999) 999-9999");
$("#new_product").validate();
BootstrapDialog.show({
type: BootstrapDialog.TYPE_PRIMARY,
message: function(dialog) {
var $message = $('<div></div>');
var pageToLoad = dialog.getData('pageToLoad');
$message.load(pageToLoad);
return $message;
},
data: {
'pageToLoad': URL_GET_VIEW_PRODUCT
},
closable: false,
buttons:[{
id: 'btn-ok',
cssClass: 'btn-primary',
icon: 'glyphicon glyphicon-send',
label: ' Save',
action: function (e) {
var description = $('#description').val();
var cost_price = $('#cost_price').val();
var selling_price = $('#selling_price').val();
var wprice = $('#wprice').val();
var min_stock = $('#min_stock').val();
var stock = $('#stock').val();
var max_stock = $('#max_stock').val();
if($("#new_product").valid()){
$.ajax({
url: URL_GET_ADD_PRODUCT,
type: 'POST',
data: {description: description, cost_price: cost_price, selling_price: selling_price, wprice: wprice, min_stock: min_stock, stock: stock, max_stock: max_stock}
}).done(function (data) {
console.log(data);
if (data.msg == 'successfully added') {
$('#new_product')[0].reset();
table.ajax.reload();
}else if(data.min_stock == 'el stock no puede ser mayor al min'){
BootstrapDialog.show({
type: BootstrapDialog.TYPE_WARNING,
message: 'el stock no puede ser mayor al min'
});
}
});
return false;
}
}
},{
id: 'btn-cancel',
cssClass: 'btn-danger',
icon: 'glyphicon glyphicon-remove',
label: ' Cancel',
action: function (e) {
e.close();
}
}]
});
});
});
I am loading an observable array via ajax, hooking up to a table and then adding sorting to the column headers. It works but only sorts random rows. If I bypass the ajax feed and manually declare the observable array, all works well. Am I missing something obvious here?
//The Page
$(document).ready(function () {
var pageModel = function () {
var self = this;
//Variables and observables
self.loading = ko.observable(false);
self.searchQuery = ko.observable("");
self.searchCelebrantId = ko.observable(-1);
//Models used in page
self.celebrantsInstance = ko.observable(new celebrantsModel());
self.marriagesInstance = ko.observable(new marriagesModel());
//var celebrantsInstance = new celebrantsModel();
//var marriageInstance = new singleMarriageModel(1);
//Get data
self.loadData = function () {
return $.when(
self.celebrantsInstance().loadData()
//, self.marriagesInstance().loadData()
);
}
}
var pageInstance = new pageModel({});
pageInstance.loadData()
.done(function () {
setTimeout(function () {
ko.applyBindings(pageInstance);
/* Bootstrap select */
$("select").selectpicker();
$("select").addClass('show-menu-arrow').selectpicker('setStyle');
}, 500);
});
});
//The knockout .js model file
function marriage(data) {
var self = this;
self.id = ko.observable(data.Id);
self.CelebrantId = ko.observable(data.CelebrantId);
self.MarriageDate = ko.observable(data.MarriageDate);
self.MarriagePlace = ko.observable(data.MarriagePlace);
self.WifeFirstName = ko.observable(data.WifeFirstName);
self.WifeMaidenName = ko.observable(data.WifeMaidenName);
self.HusbandFirstName = ko.observable(data.HusbandFirstName);
self.HusbandSurname = ko.observable(data.HusbandSurname);
self.MarriageCertificateNumberToRegistrar = ko.observable(data.MarriageCertificateNumberToRegistrar);
self.MarriageCertificateNumberToCouple = ko.observable(data.MarriageCertificateNumberToCouple);
}
function GetMarriageList(searchQuery) {
return $.ajax("/Marriage/GetMarriageList?searchQuery=" + searchQuery, {
type: "get"
});
};
function GetMarriage(id) {
return $.ajax("/Marriage/GetMarriage?id=" + id, {
type: "get"
});
};
var marriagesModel = function () {
var self = this;
self.loading = ko.observable(false);
self.searchQuery = ko.observable("a");
self.searchCelebrantId = ko.observable(-1);
self.marriages = ko.observableArray([]);
self.sortCommand = ko.observable("MarriagePlace asc");
self.headers = [
// { title: 'Marriage Date', sortPropertyName: 'MarriageDate', asc: true },
{ title: 'Marriage Place', sortPropertyName: 'MarriagePlace', asc: true },
{ title: 'Wife First Name', sortPropertyName: 'WifeFirstName', asc: true },
{ title: 'Wife Maiden Name', sortPropertyName: 'WifeMaidenName', asc: true },
{ title: 'Husband First Name', sortPropertyName: 'HusbandFirstName', asc: true },
{ title: 'Husband Surname', sortPropertyName: 'HusbandSurname', asc: true },
{ title: ' Marriage Certificate\nTo Registrar', sortPropertyName: 'MarriageCertificateNumberToRegistrar', asc: true },
{ title: 'Marriage Certificate \nTo Couple', sortPropertyName: 'MarriageCertificateNumberToCouple', asc: true },
{ title: '' },
];
self.activeSort = self.headers[0]; //set the default sort
self.sort = function (header, event) {
//if this header was just clicked a second time
if (self.activeSort === header) {
header.asc = !header.asc; //toggle the direction of the sort
} else {
self.activeSort = header; //first click, remember it
}
var prop = self.activeSort.sortPropertyName;
var ascSort = function (a, b) { return a[prop] < b[prop] ? -1 : a[prop] > b[prop] ? 1 : a[prop] == b[prop] ? 0 : 0; };
var descSort = function (a, b) { return a[prop] > b[prop] ? -1 : a[prop] < b[prop] ? 1 : a[prop] == b[prop] ? 0 : 0; };
var sortFunc = self.activeSort.asc ? ascSort : descSort;
self.marriages.sort(sortFunc);
};
self.loadData = function () {
self.loading(true);
return GetMarriageList(self.searchQuery())
.done(function (data) {
var mappedMarriages = $.map(data, function (item) {
return new marriage(item);
});
self.marriages(mappedMarriages);
self.loading(false);
});
}
return GetMarriageList(self.searchQuery())
.done(function (data) {
var mappedMarriages = $.map(data, function (item) {
return new marriage(item);
});
self.marriages(mappedMarriages);
self.loading(false);
});
}
//HTML Table
<table id="event-table" class="table table-striped" style="width: 100%; display: none" data-bind="visible: (!loading() && marriages().length > 0)">
<tr data-bind="foreach: headers">
<th data-bind="click: sort, text: title"></th>
</tr>
<!-- ko foreach: marriages -->
<tr>
<!--<td style="width: 120px"><span data-bind='html: moment(MarriageDate()).format("DD/MM/YYYY")'></span></td>-->
<td><span data-bind='html: MarriagePlace'></span></td>
<td><span data-bind='html: WifeFirstName'></span></td>
<td><span data-bind='html: WifeMaidenName'></span></td>
<td><span data-bind='html: HusbandFirstName'></span></td>
<td><span data-bind='html: HusbandSurname'></span></td>
<td><span data-bind='html: MarriageCertificateNumberToRegistrar'></span></td>
<td><span data-bind='html: MarriageCertificateNumberToCouple'></span></td>
<td><a data-bind='attr: { "href": "/Marriage/Edit/" + id }'>Edit</a></td>
</tr>
<!-- /ko -->
</table>
You might want to have a look at knockout-transformations.
Cheers