At first I have displlay data using knockout js successful,here is my code:
Js
var viewMode = {
lookupCollection: ko.observableArray()
};
$(document).ready(function () {
$.ajax({
type: "GET",
url: "/Home/GetIndex",
}).done(function (data) {
$(data).each(function (index, element) {
viewModel.lookupCollection.push(element);
});
ko.applyBindings(viewMode);
}).error(function (ex) {
alert("Error");
});
});
View:
<table class="paginated">
<tr>
<th>
Name
</th>
<th>
Price
</th>
<th>
Category
</th>
<th></th>
</tr>
<tbody data-bind="foreach: lookupCollection">
<tr>
<td data-bind="text: Name"></td>
<td data-bind="text: price"></td>
<td data-bind="text: Category"></td>
<td>
<button class="btn btn-success">Edit</button>
<button class="btn btn-danger">Delete</button>
</td>
</tr>
</tbody>
</table>
However, I need more code to paging the list items, I follow this site http://knockoutjs.com/examples/grid.html and replay my code but It has not display my list items:
JS:
var initialData = {
lookupCollection: ko.observableArray()
};
var PagedGridModel = function (items) {
this.items = ko.observableArray(items);
this.sortByName = function () {
this.items.sort(function (a, b) {
return a.name < b.name ? -1 : 1;
});
};
this.jumpToFirstPage = function () {
this.gridViewModel.currentPageIndex(0);
};
this.gridViewModel = new ko.simpleGrid.viewModel({
data: this.items,
columns: [
{ headerText: "Name", rowText: "Name" },
{ headerText: "Category", rowText: "Category" },
{ headerText: "Price", rowText: function (item) { return "$" + item.price.toFixed(2) } }
],
pageSize: 4
});
};
$(document).ready(function () {
$.ajax({
type: "GET",
url: "/Home/GetIndex",
}).done(function (data) {
$(data).each(function (index, element) {
viewModel.lookupCollection.push(element);
});
ko.applyBindings(new PagedGridModel(initialData));
}).error(function (ex) {
alert("Error");
});
});
View:
<div data-bind='simpleGrid: gridViewModel'> </div>
<button data-bind='click: sortByName'>
Sort by name
</button>
<button data-bind='click: jumpToFirstPage, enable: gridViewModel.currentPageIndex'>
Jump to first page
</button>
thankyou very much your answer:
The "simpleGrid" binding u try to use is a custom one, not available by default in knockout.
Here's a simple example for pagination using a computed observable :
Fiddle : http://jsfiddle.net/RapTorS/qLHwx/
var viewModel = function () {
var self = this;
self.pageSize = 4;
self.currentPage = ko.observable(1);
self.lookupCollection = ko.observableArray([]);
self.currentCollection = ko.computed(function () {
var startIndex = self.pageSize * (self.currentPage() - 1);
var endIndex = startIndex + self.pageSize;
return self.lookupCollection().slice(startIndex, endIndex);
});
};
Related
I want to add a css class to a item in v-for when the td in clicked
<template>
<div>
<h1>Forces ()</h1>
<section v-if="errored">
<p>We're sorry, we're not able to retrieve this information at the moment, please try back later</p>
</section>
<section v-if="loading">
<p>loading...</p>
</section>
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>#</th>
<th>ID</th>
<th
#click="orderByName = !orderByName">Forces</th>
</tr>
<th>Delete</th>
</thead>
<tbody>
<tr v-for="(force, index) in forces" #click="completeTask(force)" :class="{completed: force.done}" v-bind:key="index">
<td>
<router-link :to="{ name: 'ListForce', params: { name: force.id } }">Link</router-link>
</td>
<th>{{ force.done }}</th>
<th>{{ force.name }}</th>
<th><button v-on:click="removeElement(index)">remove</button></th>
</tr>
</tbody>
</table>
<div>
</div>
</div>
</template>
<script>
import {APIService} from '../APIService';
const apiService = new APIService();
const _ = require('lodash');
export default {
name: 'ListForces',
components: {
},
data() {
return {
question: '',
forces: [{
done: null,
id: null,
name: null
}],
errored: false,
loading: true,
orderByName: false,
};
},
methods: {
getForces(){
apiService.getForces().then((data, error) => {
this.forces = data;
this.forces.map(function(e){
e.done = false;
});
this.loading= false;
console.log(this.forces)
});
},
completeTask(force) {
force.done = ! force.done;
console.log(force.done);
},
removeElement: function (index) {
this.forces.splice(index, 1);
}
},
computed: {
/* forcesOrdered() {
return this.orderByName ? _.orderBy(this.forces, 'name', 'desc') : this.forces;
}*/
},
mounted() {
this.getForces();
},
}
</script>
<style>
.completed {
text-decoration: line-through;
}
</style>
I want a line to go through the items when clicked, but the dom doesn't update. If I go into the vue tab in chrome I can see the force.done changes for each item but only if I click out of the object and click back into it. I'm not to sure why the state isn't updating as it's done so when I have used an click and a css bind before.
I've tried to make minimal changes to get this working:
// import {APIService} from '../APIService';
// const apiService = new APIService();
// const _ = require('lodash');
const apiService = {
getForces () {
return Promise.resolve([
{ id: 1, name: 'Red' },
{ id: 2, name: 'Green' },
{ id: 3, name: 'Blue' }
])
}
}
new Vue({
el: '#app',
name: 'ListForces',
components: {
},
data() {
return {
question: '',
forces: [{
done: null,
id: null,
name: null
}],
errored: false,
loading: true,
orderByName: false,
};
},
methods: {
getForces(){
apiService.getForces().then((data, error) => {
for (const force of data) {
force.done = false;
}
this.forces = data;
this.loading= false;
console.log(this.forces)
});
},
completeTask(force) {
force.done = ! force.done;
console.log(force.done);
},
removeElement: function (index) {
this.forces.splice(index, 1);
}
},
mounted() {
this.getForces();
}
})
.completed {
text-decoration: line-through;
}
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<div id="app">
<div>
<h1>Forces ()</h1>
<section v-if="errored">
<p>We're sorry, we're not able to retrieve this information at the moment, please try back later</p>
</section>
<section v-if="loading">
<p>loading...</p>
</section>
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>#</th>
<th>ID</th>
<th
#click="orderByName = !orderByName">Forces</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
<tr v-for="(force, index) in forces" #click="completeTask(force)" :class="{completed: force.done}" v-bind:key="index">
<th>{{ force.done }}</th>
<th>{{ force.name }}</th>
<th><button v-on:click="removeElement(index)">remove</button></th>
</tr>
</tbody>
</table>
<div>
</div>
</div>
</div>
The key problem was here:
this.forces = data;
this.forces.map(function(e){
e.done = false;
});
The problem here is that the property done is being added to the data after it has been made reactive. The reactivity observers get added as soon as the line this.forces = data runs. Adding done after that counts as adding a new property, which won't work.
It's also a misuse of map so I've switched it to a for/of loop instead.
for (const force of data) {
force.done = false;
}
this.forces = data; // <- data becomes reactive here, including 'done'
On an unrelated note I've tweaked the template to move the Delete header inside the top row.
Make sure force.done is set to false in data before initialization so it is reactive.
data() {
return {
force:{
done: false;
}
}
}
If force exists but has no done member set, you can use Vue.set instead of = to create a reactive value after initialization.
Vue.set(this.force, 'done', true);
Hi everyone.
I have a question about looping over a component in vuejs.
I defined a component and also a template tag which contains a table that fetches some data from database(in laravel framework).now i need to loop over this component more than 10 times and don't know how to do this!.
i used v-for in template tag but didn't work
<div id="app">
<csgo><csgo>
</div>
<template id="match-id" >
<table style="border: 2px solid black">
<tr >
<th>Ticket</th>
<th>Number</th>
<th>Match Type</th>
<th>Date</th>
<th>Time</th>
<th>Price</th>
<th>Sold</th>
</tr>
<tr>
<td> <button #click='buy({{$user->profile->account_money}})' v-bind:style="objectStyle" :disabled=Bstate >BUY</button> </td>
<td><input type="number" min="1" max="10" step="1" v-model="ticketNumber"></td>
<td>{{$matches[0]->matchType}}</td>
<td>{{$matches[0]->matchDate}}</td>
<td>{{$matches[0]->matchTime}}</td>
<td>{{$matches[0]->price}}</td>
<td>#{{soldTicket}}#{{sold}}</td>
</tr>
</table>
</template>
<script>
Vue.component('csgo', {
template: '#match-id',
data: function () {
return {
money: '',
sold: '',
state: false,
Estate: false,
Bstate: false,
error: '',
ticketNumber: 1,
objectStyle: {
background: 'lightgreen'
},
}
},
props: ['matches'],
methods: {
buy: function (num) {
tempNum = num
num -= 1000
if (num < 0) {
this.money = tempNum
}
vm = this
axios.post('/matches/csgo-buy-ticket', {tickets:
Math.floor(vm.ticketNumber)}).then(function (response) {
if (typeof (response.data) == 'string') {
vm.error = response.data
vm.state = false
vm.Estate = !vm.state
vm.Bstate = false
}
else {
vm.money = response.data[0]
vm.sold = response.data[1]
vm.state = true
vm.Estate = !vm.state
vm.Bstate = true
vm.objectStyle.background = 'darkred'
}
})
},
},
computed: {
soldTicket: function () {
vm = this
axios.get('/sold-ticket').then(function (response) {
return vm.sold = response.data
})
},
account_money: function () {
var vm = this
axios.get('/user-account-money').then(function
(response) {
vm.money = response.data
})
},
},
})
new Vue({
el:'#app',
data:{
list:[''],
},
created:function () {
vm = this
axios.get('/csgo-matches').then(function (response) {
console.log(response.data)
vm.list = response.data
})
},
})
</script>
I have an ASP.NET 5 MVC application. I am using JQuery Datatables downloaded from Datatables.net for rendering my grid.
I want to be able to select multiple records on the grid and through the click of one button to be able to update the status feild on all my records. I can't figure out how to pass the information from javascript to my MVC controller through the view. Here is what I have so far.
View Code
<table class="display " id="ExpenseTable">
<thead>
<tr>
<th></th>
<th>
#Html.DisplayNameFor(model => model.ApplicationUserid)
</th>
<th>
#Html.DisplayNameFor(model => model.ExpenseDate)
</th>
... </tr>
</thead>
<tbody>
#foreach (var item in (IEnumerable<Expense>)ViewData["Expenses"])
{
<tr>
<td></td>
<td>
#Html.DisplayFor(modelItem => item.User.FullName)
</td>
<td>
#Html.DisplayFor(modelItem => item.ExpenseDate)
</td>
....
</tr>
}
</tbody>
</table>
#section Scripts {
<script>
//script is not complete
$(document).ready(function() {
var table = $('#ExpenseTable').DataTable({
dom: 'Bfrtip',
buttons: [
{
text: 'Approve All Selected Expenses',
action: function () {
}
}
],
columnDefs: [{
orderable: false,
className: 'select-checkbox',
targets: 0
} ],
select: {
style: 'multiple',
selector: 'td:first-child'
},
order: [[1, 'asc']],
} );
} );
I want to do something like this in the Controller
public IActionResult ApproveMany(IEnumerable<Expense> model)
{
foreach (var item in model)
{
item.Status = "Approved";
_context.Update(item);
_context.SaveChanges();
}
return RedirectToAction("StaffExpense"); ;
}
What I need help with is how I can take the button I have and when it is pushed take a collection of all the expense items that the user has selected on the grid, and then pass that collection into my controller so the edited changes can be pushed back to the database.
$('#updateButton').click(function ()
{
console.log("Selected rows: "+ table.rows('.selected').data().length);
var data = $.map(table.rows('.selected').data(), function (item)
{
console.log(item)
return item;
});
//Call your MVC Controller/API to do the update (pass data)
addData(data);
});
function addData(data)
{
//Add your controller name to url
/*POST*/
$.ajax({
url: '/Controller/ApproveMany',
dataType: "json",
type: "POST",
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(data),
cache: false,
success: function (result)
{
alert(result);
},
error: function (xhr)
{
alert('error');
}
})
}
This link would be helpful for you to get the desired solution
http://www.gyrocode.com/articles/jquery-datatables-checkboxes/
I get respons from controller
[HttpGet]
public JsonResult GetItems(string date)
{
IList<dough> modelList = new List<dough>();
modelList.Add(new dough { Type = "framed" });
modelList.Add(new dough { Type = "unframed" });
modelList.Add(new dough { Type = "soft" });
return Json(modelList, JsonRequestBehavior.AllowGet);
}
and display it in such way
<table>
<thead>
<tr><th>Waste</th></tr>
</thead>
<tbody data-bind="foreach: items">
<tr>
<td><select data-bind="options: $root.availableWastes, value: Waste, optionsText: 'Type'"></select></td>
</tr>
</tbody>
</table>
result
The main question is how to display items with default values that was getted from controller? What need to fix?
Controller:
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
return View();
}
[HttpGet]
public JsonResult GetItems(string date)
{
IList<dough> modelList = new List<dough>();
modelList.Add(new dough { Type = "framed" });
modelList.Add(new dough { Type = "unframed" });
modelList.Add(new dough { Type = "soft" });
return Json(modelList, JsonRequestBehavior.AllowGet);
}
}
class dough
{
public string Type { get; set; }
}
Index.cshtml
#{
ViewBag.Title = "Index";
}
<script src="~/Scripts/knockout-2.2.0.js"></script>
<button data-bind="click: loadItems">Load</button>
<table>
<thead>
<tr><th>Waste</th></tr>
</thead>
<tbody data-bind="foreach: items">
<tr>
<td><select data-bind="options: $root.availableWastes, value: Waste, optionsText: 'Type'"></select></td>
</tr>
</tbody>
</table>
<script>
function MyViewModel() {
var self = this;
self.availableWastes = [{ Type: "framed", score: 0 },
{ Type: "soft", score: 1 },
{ Type: "unframed", score: 2 }];
self.items = ko.observableArray();
var date = new Date();
self.loadItems = function () {
var date = new Date();
debugger;
$.ajax({
cache: false,
type: "GET",
url: "Home/GetItems",
data: { "date": date },
success: function (data) {
var result = "";
self.items.removeAll();
$.each(data, function (id, item) {
self.items.push({ Waste: item.Type });
});
},
error: function (response) {
alert('eror');
}
});
}
}
ko.applyBindings(new MyViewModel());
</script>
Looks like you want to pre-select values.
Update self.items with the Type name and Waste into an observable:
self.items.push({ Waste: ko.observable(item.Type), Type: item.Type });
Then use that in the optionsValue binding:
<select data-bind="options: $root.availableWastes, value: Waste, optionsText: 'Type', optionsValue: 'Type'">
Screenshot:
Can I change the width of search text fields in dataTables ?
I am writing following code right now but it is not working.
$('#example').dataTable()
.columnFilter({ sPlaceHolder: "head:before",
aoColumns: [ { type: "text",width:"10px" },
{ type: "date-range" },
{ type: "date-range" }
]
});
And if my dataTables is dynamically generated like as gven below:
$('#example').dataTable({
"aaData": aDataSet,
"aoColumns": [
{ "sTitle": "#","sWidth": "10px" },
{ "sTitle": "ID" },
{ "sTitle": "Staff Name" },
{ "sTitle": "Rig Days" },
{ "sTitle": "Manager"},
{ "sTitle": "Grade"},
{ "sTitle": "Tools"},
{ "sTitle": "Vacations"},
{ "sTitle": "Presently On"},
]
});
}
How to add Search field in this dynamically created DataTable to search by each column?
None of the above solution worked for me; then I got this:
$(document).ready(function () {
$('.dataTables_filter input[type="search"]').css(
{'width':'350px','display':'inline-block'}
);
});
And it worked perfectly!
If you want to place a placeholder too inside the search box use this ..
$('.dataTables_filter input[type="search"]').
attr('placeholder','Search in this blog ....').
css({'width':'350px','display':'inline-block'});
And this will work for sure.
To change the search box width, all I had to do was go into my .css file and enter the following:
.dataTables_filter input { width: 300px }
it's worked for me
<script>
var datatable = $('#table').DataTable({
...<datatables properties>,
initComplete: function () {
$('.dataTables_filter input[type="search"]').css({ 'width': '350px', 'display': 'inline-block' });
}
</script>
The only thing worked for me is this css.
$(document).ready(function(){
$('#datatable-buttons_filter').css({"position":"relative","left":"-100px"});
});
try to use css to change the width
example
.text_filter{
width:45%;
min-width:200px;
}
I applied this solution in my environment (Laravel 5.2, yajra/Laravel-DataTables 6.0, Bootstrap 3.x):
My table:
<table id="my-table" class="table table-striped table-hover" style="font-size: 80%">
<thead>
<tr>
<th class="input-filter" style="text-align:center;width: 5%">ID</th>
...
</tr>
</thead>
<tbody></tbody>
<tfoot>
<tr>
<th style="text-align:center;width: 5%">ID</th>
...
</tr>
</tfoot>
My script:
<script type="text/javascript">
var dt = $('#my-table').DataTable({
stateSave: true,
responsive: true,
processing: true,
serverSide: true,
order: [[ 0, "desc" ]],
lengthMenu: [[5, 10, -1], [5, 10, "All"]],
ajax: {
url: '...',
},
columns: [
{data: 'id', name: 'id',orderable:true,searchable:true},
...
],
language: {
url: '....'
},
initComplete: function () {
this.api().columns('.input-filter').every(function () {
var column = this;
var input = document.createElement("input");
// start - this is the code inserted by me
$(input).attr( 'style', 'text-align: center;width: 100%');
// end - this is the code inserted by me
$(input).appendTo($(column.footer()).empty())
.on('keyup', function () {
var val = $.fn.dataTable.util.escapeRegex($(this).val());
column.search(val ? val : '', true, true).draw();
});
});
}
});
</script>
here is the repeater
<asp:Repeater ID="rptClients" runat="server">
<HeaderTemplate>
<table id="example" class="display">
<thead>
<tr style="color:#fff;">
<th>Edit</th>
<th>Client Name</th>
<th>Address</th>
<th>City</th>
<th>State</th>
<th>Zip</th>
<th>Phone</th>
<th>Fax</th>
<th>Client Type</th>
<th>Active</th>
</tr>
<tr id="filterRow">
<td>Edit</td>
<td>Client Name</td>
<td>Address</td>
<td>City</td>
<td>State</td>
<td>Zip</td>
<td>Phone</td>
<td>Fax</td>
<td>Client Type</td>
<td>Active</td>
</tr>
</thead>
<tfoot style="display:none;">
<tr>
<td> </td>
</tr>
</tfoot>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td><div class="padBtm-05 padTop-10"><asp:Button runat="server" ID="btnEdit" Text="Edit" /></div></td>
<td>
<%# Container.DataItem("ClientName")%>
</td>
<td>
<%# Container.DataItem("ClientAddress")%>
</td>
<td>
<%# Container.DataItem("ClientCity")%>
</td>
<td>
<%# Container.DataItem("State")%>
</td>
<td>
<%# Container.DataItem("ClientZip")%>
</td>
<td>
<%# Container.DataItem("ClientPhone")%>
</td>
<td>
<%# Container.DataItem("ClientFax")%>
</td>
<td>
<%# Container.DataItem("ClientType")%>
</td>
<td>
<%# Container.DataItem("Active")%>
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
There are filters on all columns. Here I actually hide the edit column filter since it doesn't need one. If i don't render a filter for this column my filtering is off 1 column. In the javascript i target my table row which will end up being my title placeholder. Based on the placeholder name you can run an if statement that allows you to target the input element and set the width of the item. I have found setting the width of the filter sets the column width on the table.
// apply the input styling
$('#example thead td').each(function (i) {
var title = $('#example thead th').eq($(this).index()).text();
if (title == "Edit") {
var serach = '<input type="text" style="display:none;" placeholder="' + title + '" />';
} else if (title == "Client Name") {
var serach = '<input type="text" style="width:370px;" placeholder="' + title + '" />';
} else if (title == "Zip") {
var serach = '<input type="text" style="width:50px;" placeholder="' + title + '" />';
} else {
var serach = '<input type="text" placeholder="' + title + '" />';
}
$(this).html('');
$(serach).appendTo(this).keyup(function () { table.fnFilter($(this).val(), i) })
});
// Apply the search
table.columns().every(function () {
var that = this;
$('input', this.footer()).on('keyup change', function () {
if (that.search() !== this.value) {
that
.search(this.value)
.draw();
}
});
});
I have used the below code while using dataTables
JS
$('#du_ft_table').dataTable( { <br/>
"bProcessing": true,<br/>
"bServerSide": true,<br/>
scrollX: true,<br/>
"sAjaxSource": "../server_processing_man.php?sourceC=du_ft&rights=1&mandatory=1&retailer_id=2725",
"aoColumns": [
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
{ "mData": function(obj) {
return '<a class="btn btn-xs btn-primary" href="EBSNL_NW='+obj[0]+'" alt="Edit" title="Edit"><i class="fa fa-pencil-square-o"></i></a>';
}}
]
} );
$('.dataTables_scrollFootInner tfoot th').each( function () {<br/>
var title = $(this).text();<br/>
if(title != '') $(this).html( '<input type="text" placeholder="Search '+title+'" />' );<br/>
});
var duft_table = $('#du_ft_table').DataTable();
// Apply the search
duft_table.columns().every( function () {<br/>
var that = this;<br/>
$( 'input', this.footer() ).on( 'keyup change', function () {<br/>
if ( that.search() !== this.value ) {<br/>
that.search(this.value).draw();<br/>
}<br/>
} );
});
Nativ javascript solution.
$(document).ready(function() {
$('#yourTableId').DataTable();
var addressTableFilter = document.getElementById('addressTable_filter');
addressTableFilter.firstChild.getElementsByTagName('input')[0].style.width = "400px";
addressTableFilter.firstChild.getElementsByTagName('input')[0].setAttribute('placeholder', 'Search');
addressTableFilter.firstChild.removeChild(document.getElementById('addressTable_filter').firstChild.firstChild);
});
Dont forget to wrap everything inside document ready(if u using it)otherwise other lines may kick in before datatable is initiated and you will get error.
This will also remove search label and add it as placeholder inside input box.