Related
I want to display a table after an h1 with an id of pageHeading.
The HTML for the h1 is hardcoded: <h1 id="pageHeading">Table</h1>
const pageHeading = document.querySelector("#pageHeading")
The table is created with Javascript:
const table = document.createElement("table")
table.setAttribute("id", "table")
I tried the following:
document.body.appendChild(table)
This prints the table but after the last HTML element on the page.
Then I tried:
tableHeading.appendChild(table)
This prints the table but INSIDE the h1.
Finally, I tried:
pageHeading.insertAdjacentHTML(
"afterend",
table
)
This doesn't print the table at all. Instead I get (after the h1):
[object HTMLTableElement]
Could this be because I'm using .insertAdjacentHTML on the table contents (see full code below)?
const tableHeaders = [{
titleOne: "Name",
titleTwo: "Age",
titleThree: "Nationality",
}, ]
const persons = [{
name: "James",
age: "23",
nationality: "English",
},
{
name: "Isabella",
age: "21",
nationality: "Italian",
},
{
name: "Hank",
age: "25",
nationality: "American",
},
{
name: "Manon",
age: "27",
nationality: "French",
},
]
const pageHeading = document.querySelector("#pageHeading")
const table = document.createElement("table")
table.setAttribute("id", "table")
/* document.body.appendChild(table) this puts table AFTER the last item in the body <h2>Test</h2> */
/* tableHeading.appendChild(table) this puts table INSIDE <h1 id="tableHeading">Table</h1> */
pageHeading.insertAdjacentHTML(
"afterend",
table
) /* this returns: [object HTMLTableElement] */
const headers = tableHeaders.map(header => {
let ths = `<tr><th>${header.titleOne}</th><th>${header.titleTwo}</th><th>${header.titleThree}</th></tr>`
table.insertAdjacentHTML("afterbegin", ths)
})
const personDetails = persons.map(person => {
let tds = `<tr><td>${person.name}</td><td>${person.age}</td><td>${person.nationality}</td></tr>`
table.insertAdjacentHTML("beforeEnd", tds)
})
<h1 id="pageHeading">Table</h1>
<h2>Test</h2>
Instead of use insertAdjacentHTML you need insertAdjacentElement because is a element not an html string like:
const tableHeaders = [{
titleOne: "Name",
titleTwo: "Age",
titleThree: "Nationality",
}, ]
const persons = [{
name: "James",
age: "23",
nationality: "English",
},
{
name: "Isabella",
age: "21",
nationality: "Italian",
},
{
name: "Hank",
age: "25",
nationality: "American",
},
{
name: "Manon",
age: "27",
nationality: "French",
},
]
const pageHeading = document.querySelector("#pageHeading")
const table = document.createElement("table")
table.setAttribute("id", "table")
/* document.body.appendChild(table) this puts table AFTER the last item in the body <h2>Test</h2> */
/* tableHeading.appendChild(table) this puts table INSIDE <h1 id="tableHeading">Table</h1> */
pageHeading.insertAdjacentElement(
"afterend",
table
) /* this returns: [object HTMLTableElement] */
const headers = tableHeaders.map(header => {
let ths = `<tr><th>${header.titleOne}</th><th>${header.titleTwo}</th><th>${header.titleThree}</th></tr>`
table.insertAdjacentHTML("afterbegin", ths)
})
const personDetails = persons.map(person => {
let tds = `<tr><td>${person.name}</td><td>${person.age}</td><td>${person.nationality}</td></tr>`
table.insertAdjacentHTML("beforeEnd", tds)
})
<h1 id="pageHeading">Table</h1>
<h2>Test</h2>
Reference:
insertAdjacentHTML
insertAdjacentElement
I am a beginner in at Vue.js version 2.6.11.
I have a form where a person can add a list of toys. So the list is dynamic. How do we add this dynamic list into a JSON data structure in a POST request?
I cannot change the API.
For example the first list to send to a POST request might be
"toyCollection":
[
{
"toyName": "yo-yo",
"toyDescription": "ball on a string",
"toyAge": 15,
"company": {
"companyName": "yo yo company"
"companyYear": "1999"
}
}
]
The second time someone creates a list of toys in this dynamic list might be
"toyCollection":
[
{
"toyName": "yo-yo",
"toyDescription": "ball on a string",
"toyAge": 15,
"company": {
"companyName": "yo yo company"
"companyYear": "1999"
}
},
{
"toyName": "barbie",
"toyDescription": "dolls in a house",
"toyAge": 21,
"company": {
"companyName": "mattel"
"companyYear": "1959"
}
},
{
"toyName": "transformers",
"toyDescription": "robots in disguise",
"toyAge": 20,
"company": {
"companyName": "Hasbro"
"companyYear": "1984"
}
}
]
How do we write this in Vue so that this is dynamic?
methods: {
const postRequest = {
toyCollection: [ //if 1 toy in list
{
toyName: "yo-yo", // this.form.toyName <---- would read the data
toyDescription: "ball on a string", //hardcoded here for simplicity for example
toyAge: 15,
company: {
companyName: "yo yo company"
similarToysFromCompany: "1999"
}
}
]
}
}
If there are three toys in the collection
methods: {
const postRequest = {
toyCollection: [ //if 3 toys in list
{
toyName: "yo-yo",
toyDescription: "ball on a string",
toyAge: 15,
company: {
companyName: "yo yo company"
similarToysFromCompany: "1999"
}
},
{
toyName: "barbie",
toyDescription: "dolls in a house",
toyAge: 21,
company: {
companyName: "mattel"
companyYear: "1959"
}
},
{
toyName: "transformers",
toyDescription: "robots in disguise",
toyAge: 20,
company: {
companyName: "Hasbro"
companyYear: "1984"
}
}
]
}
}
The list can be any size, depending on how many toys a person adds to this list.
How do we make this dynamic based on the list?
Then I would call my API with this object
this.methodCallToAPI(postRequest);
Thanks for any help!
==============
EDIT
I have a template to input fields
<form>
<!-- Name -->
<input
v-model="form.toyName"
id="toy-name"
class="input"
type="text"
/>
</div>
</form>
Then in the Script, it watches or updates the data fields based on what the user types into the input text fields.
export default {
name: "CreateToyCollection",
data () {
return {
form: {
toyName: "",
toyDescription: "",
toyAge: "",
company: {
companyName: "",
similarToysFromCompany: ""
}
}
}
},
watch: {
this.form.toyName = "";
this.form.toyDescription = "";
this.form.toyAge = "";
// etc for Company
}
}
I'm working on the list part, but this is how I want to pass in the dynamic data
In the data add a new array toyCollection :
data () {
return {
toyCollection: [],
form: {
toyName: "",
...
},
...
Every time form is submitted, push the submitted data to it like this.toyCollection.push(data)
Later in your post request you can send this.toyCollection as the payload.
I am trying to mimic Excel's copy/paste within Tabulator. Simply put, I want to copy (ctrl+c) a couple of cell values and then paste them somewhere else in the table.
My idea is to:
copy a couple of cells
click on the cell where I want to start pasting from.
Store that cell's object somewhere so I can reference it when I paste the data
Ctrl+v or right click paste
Using the clicked cell I have stored as well as clipboardPasteParser callback, I would like to build a rowData object to return from that callback (as described in the docs).
Using the clipboardPasteAction callback, I will take that rowData object and use it to update the cells.
However, as far as I understand, Tabulator's clipboard functionality does not facilitate this kind of copy/paste action. In the below code snippet you will see that I console.log out the result of paste in the clipboardPasteParser(clipboard) callback. clipboard is just a concatenated string of the copied values.
For example, copying "Mary May", "1", "female", "2", and "blue", results in the string "Mary May1female2blue" in the clipboard callback variable.
Here is the code if you would like to try it out.
var data = [
{
id: 1,
name: 'Mrs. Rafaela Barton',
progress: 50,
gender: 'male',
height: 4,
col: 'GhostWhite',
dob: '02/10/1986',
driver: false
},
{
id: 2,
name: 'Grant Kunze',
progress: 16,
gender: 'female',
height: 4,
col: 'DarkViolet',
dob: '05/07/1993',
driver: true
},
{
id: 3,
name: 'Marilou Morar',
progress: 30,
gender: 'female',
height: 2,
col: 'Turquoise',
dob: '14/10/1984',
driver: true
},
{
id: 4,
name: 'Nathan Fadel Jr.',
progress: 78,
gender: 'female',
height: 4,
col: 'SkyBlue',
dob: '01/11/1921',
driver: false
},
{
id: 5,
name: 'Mrs. Amya Eichmann',
progress: 44,
gender: 'female',
height: 3,
col: 'Aquamarine',
dob: '20/02/1937',
driver: false
}
];
var table = new Tabulator("#example-table", {
height:"311px",
data: data,
columns:[
{title:"Name", field:"name", width:150},
{title:"Height", field:"height", bottomCalc:"sum"},
{title:"Progress", field:"progress", formatter:"progress", sorter:"number"},
{title:"Gender", field:"gender"},
{title:"Rating", field:"rating", formatter:"star", hozAlign:"center", width:100},
{title:"Favourite Color", field:"col"},
{title:"Date Of Birth", field:"dob", hozAlign:"center", sorter:"date"},
{title:"Driver", field:"car", hozAlign:"center", formatter:"tickCross"},
],
clipboard:true,
clipboardPasteParser: function(clipboard) {
console.log(clipboard);
},
});
<!DOCTYPE HTML>
<html>
<head>
<link href="https://unpkg.com/tabulator-tables#4.9.3/dist/css/tabulator.min.css" rel="stylesheet">
<script type="text/javascript" src="https://unpkg.com/tabulator-tables#4.9.3/dist/js/tabulator.min.js"></script>
</head>
<body>
<div id="example-table"></div>
</body>
</html>
Is there any way that I can get the callback parameter to somehow separate the values so I can parse it in the clipboardPasteParser callback? Is that possible? Am I perhaps missing something?
I have sneaking suspicion that this problem has less to do with Tabulator and more about how the browser handles copy. It would still be a nice feature if Tabulator was able to handle this natively.
Thank you!!
This is currently not possible, but cell selection will be coming in the 5.0 release in a couple of months
I am facing an issue with an excel file. I receive some data from the DB and the user should be able to replace that data with a spreadsheet that looks like this:
This is how the data comes from the DB and how the excel file should be finally formatted:
"employers": [{
"id": "4147199311345513",
"shifts": [{
"url": "https://zoom.com/983493unsdkd/",
"days": "Mon,Tue,Wed,Thu,Fri",
"name": "Morning",
"endTime": "12:00",
"timezone": "CST",
"startTime": "8:00"
}, {
"url": "https://zoom.com/983493unsdkd/",
"days": "Mon,Tue,Wed,Thu,Fri",
"name": "Afternoon",
"endTime": "12:00",
"timezone": "CST",
"startTime": "8:00"
}],
"employerUrl": "http://www.google.com",
"employerName": "AT&T",
"employerUrlText": "URL Text",
"employerLogoSmall": "assets/images/att-logo.png",
"employerDescription": "AT&T is a world premier employer with a bunch of stuff here and there."
}, {
"id": "3763171269270198",
"shifts": [{
"url": "https://zoom.com/983493unsdkd/",
"days": "Mon,Tue,Wed,Thu,Fri",
"name": "Morning",
"endTime": "12:00",
"timezone": "CST",
"startTime": "8:00"
}, {
"url": "https://zoom.com/983493unsdkd/",
"days": "Mon,Tue,Wed,Thu,Fri",
"name": "Afternoon",
"endTime": "12:00",
"timezone": "CST",
"startTime": "8:00"
}],
"employerUrl": "http://www.google.com",
"employerName": "AT&T",
"employerUrlText": "URL Text",
"employerLogoSmall": "assets/images/att-logo.png",
"employerDescription": "AT&T is a world premier employer with a bunch of stuff here and there."
}]
So I need to take that spreadsheet and format it to look like that JSON above. All of this with Javascript/React.
This is what I have so far to format my excel file and render it:
const [excelData, setExcelData] = useState({ rows: [], fileName: "" });
const fileHandler = (event) => {
let fileObj = event.target.files[0];
ExcelRenderer(fileObj, (err, resp) => {
if (err) {
console.log(err);
} else {
let newRows = [];
let shiftRows = [];
console.log(resp.rows);
resp.rows.slice(1).map((row, index) => {
if (row && row !== "undefined") {
return newRows.push({
key: index,
employer: {
name: row[0],
description: row[1],
employerUrl: row[2],
employerUrlText: row[3],
shifts: shiftRows.push({ shift: row[2] }),
},
});
}
return false;
});
setExcelData({ rows: newRows, fileName: fileObj.name });
}
});
};
That console.log above (console.log(resp.rows)) returns this:
Where the first row are the headers of the excel file.
And the code above ends up like this and it should be exactly as the JSON I mentioned:
rows: [
{
key: 0,
employer: {
name: 'AT&T',
description: 'AT&T is a world premier employer with a bunch of stuff here and there.',
shifts: 1
}
},
{
key: 1,
employer: {
shifts: 2
}
},
{
key: 2,
employer: {
shifts: 3
}
},
{
key: 3,
employer: {
shifts: 4
}
},
{
key: 4,
employer: {
name: 'Verizon',
description: 'Verizon is a world premier employer with a bunch of stuff here and there.',
shifts: 5
}
},
{
key: 5,
employer: {
shifts: 6
}
},
{
key: 6,
employer: {
shifts: 7
}
},
{
key: 7,
employer: {
shifts: 8
}
}
],
fileName: 'EmployerChats.xlsx',
false: {
rows: [
{
url: 'https://www.youtube.com/kdfjkdjfieht/',
title: 'This is a video',
thumbnail: '/assets/images/pages/5/links/0/link.png',
description: 'This is some text'
},
{
url: 'https://www.youtube.com/kdfjkdjfieht/',
title: 'This is a video',
thumbnail: '/assets/images/pages/5/links/1/link.png',
description: 'This is some text'
}
]
},
I am using this plugin to help me render the excel file: https://www.npmjs.com/package/react-excel-renderer
Any ideas on what can I do to make format the spreadsheet data as the JSON?
Please notice those empty rows.
For example every time there is a new employer name, that's a new row or item in the array, then all of the columns and rows below and after Shift Name is a new nested array of objects. Hence, this file contains an array with a length of 2 and then it contains another array of items when it hits the Shift Name column.
Is it clear?
1st of all - you don't need to follow 'original', class based setState. In FC you can just use two separate useState.
const [rows, setRows] = useState([]);
const [fileName, setFileName] = useState("");
Data conversion
I know that you need a bit different workflow, but this can be usefull (common point - data structure), too - as conversion guide, read on.
You don't need to use ExcelRenderer to operate on data from db and render it as sheet. Converted data can be exported to file later.
You can just create array of array (aoa) that follows expected view (rows = array of row cells array). To do this you need very easy algorithm:
let newData = []
map over emplyers, for each (emp):
set flag let first = true;
map over shifts, for each (shift):
if( first ) { newData.push( [emp.name, emp.descr, shift.name, shift.timezone...]); first = false;
} else newData.push( [null, null, shift.name, shift.timezone...]);
setRows( newData );
Rendering
<OutTable/> operates on data and colums props - structures similar to internal state. 'datais ourrows, we only needcolumns` prop, just another state value:
const [columns, setColumns] = useState([
{ name: "Employer name", key: 0 },
{ name: "Employer description", key: 1 },
{ name: "Shift name", key: 2 },
// ...
]);
and finally we can render it
return (
<OutTable data={rows] columns />
Later
User can operate on sheet view - f.e. insert rows using setRows() or download this as file (XLSX.writeFile()) after simple conversion:
var ws = XLSX.utils.aoa_to_sheet( columns.concat( rows ) );
There is a lot of utils you can use for conversions - see samples.
Back to your needs
We have data loaded from db, data in aoa form, rendered as sheet. I don't fully understand format you need, but for your db format conversion is simple (opposite to above) - you can follow it and adjust to your needs.
let newEmployers = [];
let empCounter = -1;
// itarate on rows, on each (`row`):
rows.map( (row) => {
// new employer
if( row[0] ) {
newEmployers.push( {
// id should be here
"employerName": row[0],
"employerDescription": row[1],
"shifts": [
{
"shiftName": row[3],
"shiftDescription": row[4],
// ...
}
]
} );
empCounter ++;
} else {
// new shift for current employer
newEmployers[empCounter].shifts.push(
{
"shiftName": row[3],
"shiftDescription": row[4],
// ...
}
);
}
});
// newEmployers can be sent to backend (as json) to update DB
I'm working on a piece of code which has used jquery ui autocomplete component in order filter searched items. I have to configure it in order to be available to search based on multi ple factors, here is my sample search array:
var availableTags = [{
name: "Smith",
family: "Johnson",
account_number: "10032",
nick_name: "Friend account",
}, {
name: "Susan",
family: "Rice",
account_number: "343243",
nick_name: "Mom Account",
}, {
name: "Joe",
family: "Austin",
account_number: "3434",
nick_name: "Partner Account",
}, {
}];
the auto complete should display name, family, account number and nick_name when displaying the suggestion box. but when each item is selected only the account_number must be inserted into the text box. user must also be able to search through name, family, account number and nick name all of them. How can i achieve this target?
You need to:
Revise the data array to contain the value parameter (this allows autocomplete to fill the input upon focus/select)
Write a custom source function that filters the data based on what user has typed
Write a custom _renderItem function that displays the data formatted to your liking
So you have:
var userData = [{
name: "Smith",
family: "Johnson",
value: "10032",
nick_name: "Friend account"
}, {
name: "Susan",
family: "Rice",
value: "343243",
nick_name: "Mom Account"
}, {
name: "Joe",
family: "Austin",
value: "3434",
nick_name: "Partner Account"
}];
$("#autocomplete").autocomplete({
source: function (request, response) {
var search = $.trim(request.term.toLowerCase());
var array = $.grep(userData, function (val) {
return
val.name.toLowerCase().indexOf(search) >= 0 ||
val.family.toLowerCase().indexOf(search) >= 0 ||
val.value.toLowerCase().indexOf(search) >= 0 ||
val.nick_name.toLowerCase().indexOf(search) >= 0;
});
response(array);
}
})
.data("ui-autocomplete")._renderItem = function (ul, item) {
var $a = $("<a></a>").text(item.name + " " + item.family);
$("<br />").appendTo($a);
$("<small></small>").text(item.nick_name).appendTo($a);
$("<br />").appendTo($a);
$("<small></small>").text(item.value).appendTo($a);
return $("<li></li>").append($a).appendTo(ul);
};
Demo here