Making load more function in Vue - javascript

Trying to make a load more button, when user click it add 10 more item into the page. But the button code is not running smoothly... I still see all items in the page, and also there is no error in the console too.. of course button is not working.
Additionally, trying to make it run with the filter function.. Thank you for any example, help.
data() {
return {
estates:[],
moreEstates: [],
moreEstFetched: false,
}
},
mounted() {
axios.get('/ajax').then((response) => {
this.estates = response.data
this.insertMarkers();
});
},
methods: {
handleButton: function () {
if(!this.moreEstFetched){
axios.get('/ajax').then((response) => {
this.moreEstates = response.data;
this.estates = this.moreEstates.splice(0, 10);
this.moreEstFetched = true;
});
}
var nextEsts = this.moreEstFetched.splice(0, 10);
this.estates.push(nextEsts);
},
},
computed: {
one: function () {
let filteredStates = this.estates.filter((estate) => {
return (this.keyword.length === 0 || estate.address.includes(this.keyword)) &&
(this.rooms.length === 0 || this.rooms.includes(estate.rooms)) &&
(this.regions.length === 0 || this.regions.includes(estate.region))});
if(this.sortType == 'price') {
filteredStates = filteredStates.sort((prev, curr) => prev.price - curr.price);
}
if(this.sortType == 'created_at') {
filteredStates = filteredStates.sort((prev, curr) => Date.parse(curr.created_at) - Date.parse(prev.created_at));
}
filteredStates = filteredStates.filter((estate) => { return estate.price <= this.slider.value});
filteredStates = filteredStates.filter((estate) => { return estate.extend <= this.sliderX.value});
filteredStates = filteredStates.filter((estate) => { return estate.m2_price <= this.sliderT.value});
return filteredStates;
},
},
<table class="table table-hover">
<thead>
<tr style="background-color: #fff ">
<th scope="col">イメージ</th>
<th style="width:175px;"scope="col">物件名</th>
<th style="width:175px;"scope="col">住所</th>
<th scope="col">販売価格</th>
<th scope="col">間取り</th>
<th scope="col">専有面積</th>
<th scope="col">坪単価</th>
<th style="width:90px;" scope="col">物件詳細</th>
</tr>
</thead>
<tbody>
<tr  v-for="estate in one">
<td><img id="image" :src="estate.image" alt=""></td>
<td>{{estate.building_name}}</td>
<td>{{estate.address}}</td>
<td>{{priceSep(estate.price)}} 万円</td>
<td>{{estate.rooms}}</td>
<td>{{xtendSep(estate.extend)}} m²</td>
<td>{{estate.m2_price}}</td>
<td><a :href="/pages/+estate.id">物件詳細</a></td>
</tr>
</tbody>
</table>
<button class="btn btn-primary loadmorebutton" #click="handleButton">Load more</button>

As #pyriand3r pointed out that the axios request is async you can do something like this with async/await without modifiyng too much the code.
methods: {
handleButton: function () {
if(!this.moreEstFetched){
axios.get('/ajax').then(async (response) => {
this.moreEstates = await response.data;
this.estates = this.moreEstates.splice(0, 10);
this.moreEstFetched = true;
});
}
// Also you cant splice a boolean only arrays.
var nextEsts = this.moreEstFetched.splice(0, 10);
this.estates.push(nextEsts);
},
},
See: Async/await in JavaScript

Made some changes to your code, read the comment to understand.
But this is the same as the last post you added.
data() {
return {
visible:true ,
estates:[],
moreEstates: [],
moreEstFetched: false,
size: 10,
selectedPage:0,
init: false,
}
},
updated: function () { // when loaded, trigger only once
if (!this.init) {
this.handleButton();
this.init = true;
}
},
mounted() {
// why is this here, you should only have handleButton to load the data
// axios.get('/ajax').then((response) => {
// this.estates =this.filterData(response.data)
// this.insertMarkers();
// this.showMore();
// });
},
methods: {
filterData: function (data) {
let filteredStates = data.filter((estate) => {
return (this.keyword.length === 0 || estate.address.includes(this.keyword)) &&
(this.rooms.length === 0 || this.rooms.includes(estate.rooms)) &&
(this.regions.length === 0 || this.regions.includes(estate.region))});
if(this.sortType == 'price') {
filteredStates = filteredStates.sort((prev, curr) => prev.price - curr.price);
}
if(this.sortType == 'created_at') {
filteredStates = filteredStates.sort((prev, curr) => Date.parse(curr.created_at) - Date.parse(prev.created_at));
}
filteredStates = filteredStates.filter((estate) => { return estate.price <= this.slider.value});
filteredStates = filteredStates.filter((estate) => { return estate.extend <= this.sliderX.value});
filteredStates = filteredStates.filter((estate) => { return estate.m2_price <= this.sliderT.value});
return filteredStates;
},
showMore: function(){
if (Math.ceil( this.moreEstates.length / this.size) <= this.selectedPage +1 ){
this.selectedPage++;
// using slice is better where splice changes the orginal array
var nextEsts = this.moreEstFetched.slice((this.selectedPage * this.size), this.size);
this.estates.push(nextEsts);
}else this. visible= true; // hide show more
},
handleButton: function () {
if(!this.moreEstFetched){
axios.get('/ajax').then((response) => {
// filter the whole data at once
this.moreEstates = this.filterData(response.data);
this.moreEstFetched = true;
// not sure what this is, i moved it here
this.insertMarkers();
this.showMore();
});
}else this.showMore();
},
},
<table class="table table-hover">
<thead>
<tr style="background-color: #fff ">
<th scope="col">イメージ</th>
<th style="width:175px;"scope="col">物件名</th>
<th style="width:175px;"scope="col">住所</th>
<th scope="col">販売価格</th>
<th scope="col">間取り</th>
<th scope="col">専有面積</th>
<th scope="col">坪単価</th>
<th style="width:90px;" scope="col">物件詳細</th>
</tr>
</thead>
<tbody>
<tr v-for="estate in estates">
<td><img id="image" :src="estate.image" alt=""></td>
<td>{{estate.building_name}}</td>
<td>{{estate.address}}</td>
<td>{{priceSep(estate.price)}} 万円</td>
<td>{{estate.rooms}}</td>
<td>{{xtendSep(estate.extend)}} m²</td>
<td>{{estate.m2_price}}</td>
<td><a :href="/pages/+estate.id">物件詳細</a></td>
</tr>
</tbody>
</table>
<button v-if="visible" class="btn btn-primary loadmorebutton" #click="handleButton">Load more</button>

actually, I am not sure it is the best way but, tried much more simplest way to achieve it...
data() {
return {
moreEstates: 10,
}
},
<table class="table table-hover">
<tbody>
<tr v-if="moreIndex < one.length"  v-for="moreIndex in moreEstates">
<td><img id="image" :src="one[moreIndex].image" alt=""></td>
<td>{{one[moreIndex].building_name}}</td>
<td>{{one[moreIndex].address}}</td>
<td>{{priceSep(one[moreIndex].price)}} 万円</td>
<td>{{one[moreIndex].rooms}}</td>
<td>{{xtendSep(one[moreIndex].extend)}} m²</td>
<td>{{one[moreIndex].m2_price}}</td>
<td><a :href="/pages/+one[moreIndex].id">物件詳細</a></td>
</tr>
</tbody>
</table>
<button class="btn btn-primary loadmorebutton" #click="moreEstates += 10">次の10件を見る</button>

Related

I want to refactor the code to have less functions

How would I go about refactoring my code to be more concise:
const an1 = document.getElementById("an1");
const bt1 = document.getElementById("bt1");
bt1.addEventListener("click", () => {
if (an1.value.toLowerCase() === "test") {
document.getElementById("bt1").style.display = "none";
document.getElementById("an1").style.display = "none";
document.getElementById("wo1").style.display = "initial";
} else {
bt1.innerText = "Wrong!";
document.getElementById("bt1").style.background = "red";
}
});
const an2 = document.getElementById("an2");
const bt2 = document.getElementById("bt2");
bt2.addEventListener("click", () => {
if (an2.value.toLowerCase() === "test1") {
document.getElementById("bt2").style.display = "none";
document.getElementById("an2").style.display = "none";
document.getElementById("wo2").style.display = "initial";
} else {
bt2.innerText = "Wrong!";
document.getElementById("bt2").style.background = "red";
}
});
<tr>
<td class="c1"><input id="an1" placeholder="test" type="text" onblur="this.value=removeSpaces(this.value);" /><a id="wo1" style="display: none;">test</a><button id="bt1">Submit</button></td>
<td class="c1">test</td>
</tr>
<tr>
<td class="c2"><input id="an2" placeholder="test1" type="text" onblur="this.value=removeSpaces(this.value);" /><a id="wo2" style="display: none;">test1</a><button id="bt2">Submit</button></td>
<td class="c2">test1</td>
</tr>
Try below code, update the arrays if this fucntionality requires for others field too.
// change below arrays if you need this functionality for more fields
const expectedElementAnswer = [{ id: 'an1', expectAns: 'test' }, { id: 'an2', expectAns: 'test1' }];
const btnElementList = [
[{ id: 'bt1', displayValue: 'none' },{ id: 'an1', displayValue: 'none' }, { id: 'wo1', displayValue: 'initial' }],
[{ id: 'bt2', displayValue: 'none' }, { id: 'an2', displayValue: 'none' }, { id: 'wo2', displayValue: 'initial' }]
];
document.getElementById('myTable').addEventListener('click', (event) => {
const curElemetId = event.target.id;
const btnIndex = (curElemetId === 'bt1') ? 1 : (curElemetId === 'bt2') ? 2 : -1;
if ((btnIndex === 1) || (btnIndex === 2)) {
const idx = btnIndex - 1;
const { id, expectAns } = expectedElementAnswer[idx];
if (getElementValue(id).toLowerCase() === expectAns) {
changeDisplayStyles(idx);
} else {
setErrorWarning(curElemetId);
}
}
});
function changeDisplayStyles(idx) {
btnElementList[idx].forEach(({ id, displayValue }) => {
setDisplayStyle(id, displayValue)
});
}
function setDisplayStyle(displayId, value) {
document.getElementById(displayId).style.display = value;
}
function setErrorWarning(displayId, bgColor = 'red') {
const element = document.getElementById(displayId);
element.innerText = 'Wrong!';
element.style.background = bgColor;
}
function getElementValue(id) {
const value = document.getElementById(id)?.value || '';
return value;
}
<table id="myTable">
<tr>
<td class="c1">
<input id="an1" placeholder="test" type="text"/>
<a id="wo1" style="display: none;">test</a>
<button id="bt1">Submit</button>
</td>
<td class="c1">test</td>
</tr>
<tr>
<td class="c2">
<input id="an2" placeholder="test1" type="text"/>
<a id="wo2" style="display: none;">test1</a>
<button id="bt2">Submit</button>
</td>
<td class="c2">test1</td>
</tr>
</table>

Append ajax response to html table

I have an AJAX function that returns this json array when the page loads.
{
"ydtd4EGwIgb9QAPekbzBUXq9ZXp2":{
"Highscore":1000,
"username":"ash"
},
"qo80G8bFPsRkujLm9qWtASz0TE32":{
"Highscore":900,
"username":"pink"
},
"oyWEgmEAMENvr8zTGd6gqCMyVPS2":{
"Highscore":800,
"username":"orange"
},
"acjqiNwlxqfZsSaRBYKoaVOqomh1":{
"Highscore":700,
"username":"white"
},
"IhnWPgRT1gVLrxLhD6ZvNn9migX2":{
"Highscore":"700",
"username":"RED"
},
"ZeGUezY38gcHX0NXaommRPR65cR2":{
"Highscore":600,
"username":"blue"
},
"A41jXf0wmQQqzUlAu6WAuaf04Nk2":{
"Highscore":600,
"username":"mary"
},
"Vm4jMNI83mSFdN4wYbfJ6C7ecEH3":{
"Highscore":500,
"username":"green"
},
"PtTdYXIWYAeMOrIPE8FBN66F9L32":{
"Highscore":400,
"username":"gray"
},
"OeUusBMYjBSYg6UJ8I3eze2TUHi2":{
"Highscore":300,
"username":"yellow"
},
"9xn2ZH9m63Rs34Erkz6N69kuE653":{
"Highscore":100,
"username":"violet"
}
}
what I want is to append only the high score and the username but not the uid into the table so it would populate the table once the page loads.
<table class="table table-borderless table-dark table-striped" id="records_table">
<tr>
<th style="text-align: center;">Rank</th>
<th style="text-align: center;">Username</th>
<th style="text-align: center;">Highscore</th>
</tr>
</table>
I tried each loop but I can't get it to work, any help is appreciated.
var obj ={
"ydtd4EGwIgb9QAPekbzBUXq9ZXp2":{
"Highscore":1000,
"username":"ash"
},
"qo80G8bFPsRkujLm9qWtASz0TE32":{
"Highscore":900,
"username":"pink"
},
"OeUusBMYjBSYg6UJ8I3eze2TUHi2":{
"Highscore":1200,
"username":"yellow"
},
"9xn2ZH9m63Rs34Erkz6N69kuE653":{
"Highscore":100,
"username":"violet"
}
}
var res = Object.keys(obj).map((data)=>{
var innerdata = obj[data];
var score = innerdata.Highscore;
var username = innerdata.username;
return [score,username]
})
var result = res.sort((a,b)=> b[0]-a[0])
var final = Object.keys(result).map((rank)=>{
var Rank =Number(rank)+1;
var score = result[rank][0];
var name = result[rank][1]
document.querySelector('table > tbody').innerHTML += `
<tr><td>${Rank}</td><td>${name}</td><td>${score}</td></tr>`;
})
It is simple. You just need to iterate over each object.
Like this:
const data = {
"ydtd4EGwIgb9QAPekbzBUXq9ZXp2":{
"Highscore":1000,
"username":"ash"
},
"qo80G8bFPsRkujLm9qWtASz0TE32":{
"Highscore":900,
"username":"pink"
},
"oyWEgmEAMENvr8zTGd6gqCMyVPS2":{
"Highscore":800,
"username":"orange"
},
"acjqiNwlxqfZsSaRBYKoaVOqomh1":{
"Highscore":700,
"username":"white"
},
"IhnWPgRT1gVLrxLhD6ZvNn9migX2":{
"Highscore":"700",
"username":"RED"
},
"ZeGUezY38gcHX0NXaommRPR65cR2":{
"Highscore":600,
"username":"blue"
},
"A41jXf0wmQQqzUlAu6WAuaf04Nk2":{
"Highscore":600,
"username":"mary"
},
"Vm4jMNI83mSFdN4wYbfJ6C7ecEH3":{
"Highscore":500,
"username":"green"
},
"PtTdYXIWYAeMOrIPE8FBN66F9L32":{
"Highscore":400,
"username":"gray"
},
"OeUusBMYjBSYg6UJ8I3eze2TUHi2":{
"Highscore":300,
"username":"yellow"
},
"9xn2ZH9m63Rs34Erkz6N69kuE653":{
"Highscore":100,
"username":"violet"
}
};
for (const key in data) {
const {Highscore, username, rank = "???"} = data[key];
document.querySelector('table > tbody').innerHTML += `
<tr><td>${rank}</td><td>${username}</td><td>${Highscore}</td></tr>`;
}
<table>
<thead>
<th style="text-align: center;">Rank</th>
<th style="text-align: center;">Username</th>
<th style="text-align: center;">Highscore</th>
</thead>
<tbody></tbody>
</table>

twbsPagination is not a function

The pagination page numbers looks weird and lengthy. I want to display only some of the page numbers in frontend. my code It's working ok, but not good when there's large numbers of pages. so i'm using twbsPagination in function renderPagination. when i run my code i'm getting the error Uncaught TypeError: $(...).twbsPagination is not a function. twbsPagination source is script:src pagination.js. but when i run twbsPagination separate without any function it's working fine. how can i run twbsPagination with my code?
index.html
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css" integrity="sha512-+4zCK9k+qNFUR5X+cKL9EIR+ZOhtIloNl9GIKS57V1MyNsYpYcUrUeQc9vNfzsWfV28IaLL3i96P9sdNyeRssA==" crossorigin="anonymous" />
<script src="homer/vendor/jquery/dist/jquery.min.js"></script>
<script src="desk/vendor/pagination/pagination.min.js"></script>
<script src="desk/components/approved2.js"></script>
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
</tr>
</thead>
<tbody id="approvedList">
</tbody>
</table>
<nav aria-label="Page navigation example">
<ul class="pagination"></ul>
</nav>
index.js
const localURL = "http://localhost:8000/"
// output Html
const Story = document.querySelector('#approvedList');
const pagination = document.querySelector('.pagination');
$(function () {
var page = 1,
records = 1,
totalRecords = 0,
search = '';
// Run on page load
fetchData();
setInterval(fetchData, 2000);
// data filtering
$("#search-input").keyup(function (e) {
let value = e.target.value
fetchData(search = value);
});
// Show Records limits
$("#records").click(function (e) {
let value = e.target.value
fetchData(records = value);
});
// Previous Page
$('[aria-label="Previous"]').click(function () {
if (page > 1) {
page--;
}
fetchData();
});
// Next page
$('[aria-label="Next"]').click(function () {
if (page * records < totalRecords) {
page++;
}
fetchData();
});
// data fetching from API
function fetchData() {
$.ajax({
url: "http://localhost:8000/api/approved/",
type: "GET",
data: {
page: page,
records: records,
search: search
},
success: function (res) {
totalRecords = res.count
Story.innerHTML = '';
res.results.map((object) => {
Story.innerHTML +=
`<tr>
<td> ` + object.id + `</td>
<td>${object.id}` + object.title + `</td>
</tr>`;
})
Pagination();
}
})
}
function Pagination() {
// let pagesNumbers = Math.ceil(totalRecords / records);
let pagesNumbers = Math.ceil(totalRecords / records);
$('#pagination').twbsPagination({
totalPages: pagesNumbers,
visiblePages: 5,
onPageClick: function (event, page) {
$('#page-content').text('Page ' + page);
}
});
}
})
You cannot add twice the jQuery library.
I don't know the pagination.min.js and approved2.js libraries but I know you can add the twbsPagination as follow:
<script src="https://cdnjs.cloudflare.com/ajax/libs/twbs-pagination/1.4.2/jquery.twbsPagination.min.js"></script>
Moreover, this line is wrong:
let pagesNumbers = Math.ceil(totalRecords / records);
pagesNumbers needs to be at least 1.
The snippet with your code:
const fakeData = {
data: [{
row: 1,
name: 'a'
}, {
row: 2,
name: 'b'
}, {
row: 3,
name: 'c'
}, {
row: 4,
name: 'd'
}, {
row: 5,
name: 'e'
}, {
row: 6,
name: 'f'
}, {
row: 7,
name: 'g'
}],
totalRecords: 7
};
// output Html
const Story = document.querySelector('#approvedList');
const pagination = document.querySelector('.pagination');
$(function () {
var page = 1,
records = 1,
totalRecords = 0,
search = '';
// Run on page load
fetchData();
// data fetching from API
function fetchData() {
totalCount = fakeData.totalCount;
Story.innerHTML = '';
fakeData.data.slice((page - 1) * records, page * records).map((object) => {
Story.innerHTML +=
`<tr >
<td>${object.row}</td>
<td>${object.name}</td>
</tr >
`;
})
renderPagination();
}
function renderPagination() {
let pagesNumbers = Math.ceil(totalRecords / records) || 1;
$('.pagination').twbsPagination({
totalPages: pagesNumbers,
visiblePages: 5,
onPageClick: function (event, page) {
$('#page-content').text('Page ' + page);
}
});
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/twbs-pagination/1.4.2/jquery.twbsPagination.min.js"></script>
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
</tr>
</thead>
<tbody id="approvedList">
</tbody>
</table>
<nav aria-label="Page navigation example">
<ul class="pagination"></ul>
</nav>

Element.DataTable is not a function?

I am using smart admin theme.
I am trying to implement data table but it's show the error
ement.DataTable is not function
my console shows the following error
ERROR TypeError: element.DataTable is not a function
table.ts file code is given below
ngOnInit() {
setTimeout(()=>{this.render()},500);
}
render() {
let element = $(this.el.nativeElement.children[0]);
let options = this.options || {};
let toolbar = "";
if (options.buttons) toolbar += "B";
if (this.paginationLength) toolbar += "l";
if (this.columnsHide) toolbar += "C";
if (typeof options.ajax === "string") {
let url = options.ajax;
options.ajax = {
url: "./../../assets/datatables.standard.json"
// complete: function (xhr) {
//
// }
};
}
options = $.extend(options, {
dom:
"<'dt-toolbar'<'col-xs-12 col-sm-6'f><'col-sm-6 col-xs-12 hidden-xs text-right'" +
toolbar +
">r>" +
"t" +
"<'dt-toolbar-footer'<'col-sm-6 col-xs-12 hidden-xs'i><'col-xs-12 col-sm-6'p>>",
oLanguage: {
sSearch:
"<span class='input-group-addon'><i class='glyphicon glyphicon-search'></i></span> ",
sLengthMenu: "_MENU_"
},
autoWidth: false,
retrieve: true,
responsive: true,
initComplete: (settings, json) => {
element
.parent()
.find(".input-sm")
.removeClass("input-sm")
.addClass("input-md");
}
});
console.log("_dataTable");
console.log(element);
const _dataTable = element.DataTable(options);
if (this.filter) {
// Apply the filter
element.on("keyup change", "thead th input[type=text]", function() {
_dataTable
.column(
$(this)
.parent()
.index() + ":visible"
)
.search(this.value)
.draw();
});
}
if (!toolbar) {
element
.parent()
.find(".dt-toolbar")
.append(
'<div class="text-right"><img src="assets/img/logo.png" alt="SmartAdmin" style="width: 111px; margin-top: 3px; margin-right: 10px;"></div>'
);
}
if (this.detailsFormat) {
let format = this.detailsFormat;
element.on("click", "td.details-control", function() {
var tr = $(this).closest("tr");
var row = _dataTable.row(tr);
if (row.child.isShown()) {
row.child.hide();
tr.removeClass("shown");
} else {
row.child(format(row.data())).show();
tr.addClass("shown");
}
});
}
}
table.html file code is given below
<table class="dataTable responsive {{tableClass}}" width="{{width}}">
<ng-content></ng-content>
</table>
app.component.ts code is given below
public REST_ROOT = 'https://jsonplaceholder.typicode.com';
options = {
dom: "Bfrtip",
ajax: (data, callback, settings) => {
this.http.get(this.REST_ROOT + '/posts')
.pipe(
map((data: any)=>(data.data || data)),
catchError(this.handleError),
)
.subscribe((data) => {
console.log('data from rest endpoint', data);
callback({
aaData: data.slice(0, 100)
})
})
},
columns: [
{ data: "userId" },
{ data: "id" },
{ data: "title" },
{ data: "body" },
]
};
constructor(private http: HttpClient) { }
ngOnInit() {}
private handleError(error: any) {
// In a real world app, we might use a remote logging infrastructure
// We'd also dig deeper into the error to get a better message
let errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
console.error(errMsg); // log to console instead
return Observable.throw(errMsg);
}
app.component.html code is given below
<div color="blueDark">
<header>
<span class="widget-icon"> <i class="fa fa-table"></i> </span>
<h2>Datatables Rest Demo</h2>
</header>
<div>
<div class="widget-body no-padding">
<app-table [options]="options" tableClass="table table-striped table-bordered table-hover">
<thead>
<tr>
<th [style.width]="'8%'" data-hide="mobile-p">User ID</th>
<th [style.width]="'8%'" data-hide="mobile-p">Post ID</th>
<th>Title</th>
<th data-class="expand">Body</th>
</tr>
</thead>
<tfoot>
<tr>
<th>User ID</th>
<th>Post ID</th>
<th>Title</th>
<th>Body</th>
</tr>
</tfoot>
</app-table>
</div>
</div>
</div>

make row clickable after refresh in mvc

I want to make a row clickable after a refresh. I have this in the view:
#foreach (var item in Model) {
<tr class="#(item.Id == (int)(Session["Id"] ?? 0) ? ".tr.sfs-selected .table.sfs-selectable tbody .dataTable sfs-selected .dataTable sfs-selectable .table-responsive" : String.Empty)" onclick="'<tr>'" data-url="#Url.Action("Index", new RouteValueDictionary { { "id", item.Id } })">
<td>
#Html.DisplayFor(modelItem => item.Id)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.IsEnabled)
</td>
<td>
</tr>
}
I have this jQuery:
$("table.sfs-selectable tbody").on("click", "tr", function (ev) {
var $row = $("tr.sfs-selected").each(function(){
selectRow($row, !$row.hasClass("sfs-selected"));
});
});
However the row is not clicked after refresh.
Thank you
the view:
<table class="table table-striped table-bordered table-hover dataTable sfs-selectable sfs-col1-right-aligned">
<thead>
<tr>
<th>
#Html.RouteLink(Html.DisplayNameFor(model => firstItem.Id).ToString(), "Sort-Product", new { sortColumn = "id", sortOrder = (ViewBag.sortColumn == "id" && ViewBag.sortOrder != "desc") ? "desc" : "", searchString = ViewBag.SearchString, filter = ViewBag.Filter })
#ViewHelper.GetSortIndicator("id", ViewBag.sortColumn, ViewBag.sortOrder)
</th>
<th>
#Html.RouteLink(Html.DisplayNameFor(model => firstItem.Name).ToString(), "Sort-Product", new { sortColumn = "name", sortOrder = (ViewBag.sortColumn == "name" && ViewBag.sortOrder != "desc") ? "desc" : "", searchString = ViewBag.SearchString, filter = ViewBag.Filter })
#ViewHelper.GetSortIndicator("name", ViewBag.sortColumn, ViewBag.sortOrder)
</th>
<th>
#Html.RouteLink(Html.DisplayNameFor(model => firstItem.IsEnabled).ToString(), "Sort-Product", new { sortColumn = "enabled", sortOrder = (ViewBag.sortColumn == "enabled" && ViewBag.sortOrder != "desc") ? "desc" : "", searchString = ViewBag.SearchString, filter = ViewBag.Filter })
#ViewHelper.GetSortIndicator("enabled", ViewBag.sortColumn, ViewBag.sortOrder)
</th>
<th>
#Html.RouteLink(Html.DisplayNameFor(model => firstItem.FormName).ToString(), "Sort-Product", new { sortColumn = "formname", sortOrder = (ViewBag.sortColumn == "formname" && ViewBag.sortOrder != "desc") ? "desc" : "", searchString = ViewBag.SearchString, filter = ViewBag.Filter })
#ViewHelper.GetSortIndicator("formname", ViewBag.sortColumn, ViewBag.sortOrder)
</th>
<th>
#Html.RouteLink(Html.DisplayNameFor(model => firstItem.TemplateName).ToString(), "Sort-Product", new { sortColumn = "design", sortOrder = (ViewBag.sortColumn == "design" && ViewBag.sortOrder != "desc") ? "desc" : "", searchString = ViewBag.SearchString, filter = ViewBag.Filter })
#ViewHelper.GetSortIndicator("design", ViewBag.sortColumn, ViewBag.sortOrder)
</th>
<th>
#Html.RouteLink(Resources.Entity.Product.PublicUrl, "Sort-Product", new { sortColumn = "urlname", sortOrder = (ViewBag.sortColumn == "urlname" && ViewBag.sortOrder != "desc") ? "desc" : "", searchString = ViewBag.SearchString, filter = ViewBag.Filter })
#ViewHelper.GetSortIndicator("urlname", ViewBag.sortColumn, ViewBag.sortOrder)
</th>
<th>
#Html.DisplayNameFor(model => firstItem.SubmittedForms)
</th>
<th>
#Html.RouteLink(Html.DisplayNameFor(model => firstItem.ModificationDate).ToString(), "Sort-Product", new { sortColumn = "modified", sortOrder = (ViewBag.sortColumn == "modified" && ViewBag.sortOrder != "desc") ? "desc" : "", searchString = ViewBag.SearchString })
#ViewHelper.GetSortIndicator("modified", ViewBag.sortColumn, ViewBag.sortOrder)
</th>
<th class="hidden"></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model) {
<tr class="#(item.Id == (int)(Session["Id"] ?? 0) ? ".tr.sfs-selected .table.sfs-selectable tbody .dataTable sfs-selected .dataTable sfs-selectable .table-responsive" : String.Empty)" data-url="#Url.Action("Index", new RouteValueDictionary { { "id", item.Id } })">
<td>
#Html.DisplayFor(modelItem => item.Id)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.IsEnabled)
</td>
<td>
#{
bool viewLink = item.IsEnabled;
if (!String.IsNullOrEmpty(item.FormName)) {
var form = item.FormLibraryEntry;
if (form == null) {
viewLink = false;
#Html.DisplayFor(modelItem => item.FormName)
<em>(#Resources.Entity.Environment.Removed)</em>
}
else {
#Html.DisplayFor(modelItem => form.Name)
<i class="fa fa-fw fa-external-link-square text-info"></i>
}
}
}
</td>
<td>
#{
if (!String.IsNullOrEmpty(item.TemplateName)) {
var template = item.TemplateLibraryEntry;
if (template == null) {
viewLink = false;
#Html.DisplayFor(modelItem => item.TemplateName)
<em>(#Resources.Entity.Environment.Removed)</em>
}
else {
#Html.DisplayFor(modelItem => template.Name)
<i class="fa fa-fw fa-external-link-square text-info"></i>
}
}
}
</td>
<td>
#if (!String.IsNullOrEmpty(item.UrlName)) {
var defaultProductUri = CustomerConfig.ToHostUri(Request.Url.Scheme, defaultHostHeader, Request.Url.Port, (isProduction ? "" : "TEST/") + item.UrlName);
if (viewLink) {
#item.UrlName
<i class="fa fa-fw fa-external-link-square text-info"></i>
}
else {
#item.UrlName
}
}
</td>
<td>
#{
int cnt = item.SubmittedForms.Where(prod => prod.Order.IsProduction == isProduction).Count();
#(cnt.ToString() + " ")
if (cnt > 0) {
<a href="#Url.Action("Index", "SubmittedForms", new { filter = item.Id })">
<i class="fa fa-fw fa-external-link-square text-info"></i>
</a>
}
}
</td>
<td class="text-nowrap">
#item.ModificationDate.ToString("G")
</td>
<td class="hidden">
<span>
#if (!String.IsNullOrEmpty(item.UrlName) && !String.IsNullOrEmpty(item.FormName)) {
#Html.RouteLink(Resources.Action.Navigation.Preview, "ProductPreview", new { productUrl = item.UrlName, customerSchema = custSchema }, new { target = "_blank" })
}
else { #(Resources.Action.Navigation.Preview) }
| #Html.ActionLink(Resources.Action.Navigation.Details, "Details", new { id = item.Id })
| #Html.ActionLink(Resources.Action.Navigation.Edit, "Edit", new { id = item.Id })
</span>
</td>
</tr>
}
</tbody>
</table>
so I have tbody in it. but the problem is now that I have to double click on a row
this is the selectRow function:
function selectRow($row, doSel) {
var $section = $row.closest("section");
if (doSel) {
$section.find("tr.sfs-selected").removeClass("sfs-selected");
$row.addClass("sfs-selected");
$section.find(".sfs-actionbutton").each(function (index) {
var $btn = $(this);
$btn.addClass("disabled");
var href = $row.find("td:last a").filter(function () {
return $(this).text().trim() == $btn.text().trim();
}).attr("href");
if (href) {
$btn.attr("href", href).removeClass("disabled");
if ($btn.parent().is(".btn-group")) {
$btn.parent().children("a").removeClass("disabled");
$btn.attr("data-href", href + "/");
$btn.attr("href", href + "/" + $(".sfs-select-preview-template .active a").attr("href"));
}
}
});
}
else {
$row.removeClass("sfs-selected");
$section.find(".sfs-actionbutton").addClass("disabled");
}
}
You just have wrong selector, i gess it should be like this:
var $row = $("tr.sfs-selected").each(function(){
selectRow( $(this), $(this).hasClass("sfs-selected"));
});
The point is in each() method you can get one of collection element with this keyword.
You seem to be specifying class names by adding leading dots . to them, but I don't think you mean to have them like that (or the jQuery selectors won't work). Also the inline onclick is not in a working state, but your jQuery event should take care of that so that can be removed.
<tr class="#(item.Id == (int)(Session["Id"] ?? 0) ? "sfs-selected sfs-selectable" : String.Empty)" data-url="#Url.Action("Index", new RouteValueDictionary { { "id", item.Id } })">
Now, I am assuming you don't really want a classes named tbody dataTable table-responsive on each row either, so I removed them. They should probably be set on the <table> and/or <tbody> but if you need them back just re-add them.
For you jQuery:
The call to selectRow() seems a bit odd, since it will only iterate table rows with class sfs-selected, hence it will always call the function with selectRow($(element), false).
In other words: when you click a table row any row with class sfs-selected will have it's class removed and actionbutton will be disabled. Is this the desired behavior?

Categories

Resources