I'd like to make the first row read only - which I've done - and include placeholder values for the data input requirements, e.g., a date format of yyyy-mm-dd. I can add placeholder values to all cells (by setting the Placeholder property), but can't figure out how to add a placeholder to a single cell. Thanks in advance for your help.
var placeHolders = {
"course_id": "ABC ",
"class_date": "YYYY-MM-DD",
"sponsor_name": "ICPAS",
"title": "How to",
"subject": "Audit",
"description": "Auditing 101",
"hours_preparation": "2.0",
"hours_presentation": "2.0",
"hours_semester": "2.0",
"hours_quarter": "2.0",
"hours_earned": "2.0",
"price": "25.00",
"link": "www.bastute.com"
};
var data = [];
var greenRenderer = function (instance, td, row, col, prop, value, cellProperties) {
Handsontable.renderers.TextRenderer.apply(this, arguments);
td.style.backgroundColor = 'green';
};
var data = [];
function strip_tags(input, allowed) {
// + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
allowed = (((allowed || "") + "").toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join(''); // making sure the allowed arg is a string containing only tags in lowercase (<a><b><c>)
var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
return input.replace(commentsAndPhpTags, '').replace(tags, function ($0, $1) {
return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
});
};
var safeHtmlRenderer = function (instance, td, row, col, prop, value, cellProperties) {
var escaped = Handsontable.helper.stringify(value);
escaped = strip_tags(escaped, '<em><b><strong><a><big>'); //be sure you only allow certain HTML tags to avoid XSS threats (you should also remove unwanted HTML attributes)
td.innerHTML = escaped;
return td;
};
function negativeValueRenderer(instance, td, row, col, prop, value, cellProperties) {
Handsontable.renderers.TextRenderer.apply(this, arguments);
if (parseInt(value, 10) < 0) { //if row contains negative number
td.className = 'negative'; //add class "negative"
}
if (!value || value === '') {
td.style.background = '#EEE';
}
};
Handsontable.renderers.registerRenderer('negativeValueRenderer', negativeValueRenderer); //maps function to lookup string
var container = document.getElementById('hot');
var hot = new Handsontable(container,
{
data: [],
dataSchema: {course_id: null, class_date: null, sponsor_name: null, title: null, subject: null, description: null, hours_preparation: null, hours_presentation: null, hours_semester: null, hours_quarter: null, hours_earned: null, price: null, link: null},
columns: [{
data: "course_id",
placeholder: placeHolders.course_id
},{
data: "class_date",
placeholder: placeHolders.class_date
},{
data: "sponsor_name",
placeholder: placeHolders.sponsor_name
},{
data: "title",
placeholder: placeHolders.title
},{
data: "subject",
placeholder: placeHolders.subject
},{
data: "description",
placeholder: placeHolders.description
},{
data: "hours_preparation",
placeholder: placeHolders.hours_preparation
},{
data: "hours_presentation",
placeholder: placeHolders.hours_presentation
},{
data: "hours_semester",
placeholder: placeHolders.hours_semester
},{
data: "hours_quarter",
placeholder: placeHolders.hours_quarter
},{
data: "hours_earned",
placeholder: placeHolders.hours_earned
},{
data: "price",
placeholder: placeHolders.price
},{
data: "link",
placeholder: placeHolders.link
} ],
startRows: 25,
startCols: 13,
currentRowClassName: 'currentRow',
currentColClassName: 'currentCol',
autoColumnSize: true,
autoRowSize: true,
autoWrapCol: true,
autoWrapRow: true,
rowHeaders: true,
colWidths: [50,50,50,50,50,50,50,50,50,50,50,50,50],
colHeaders: ["Course<br/>Id", "Class<br/>Date", "Sponsor<br/>Name", "<br/>Title", "<br/>Subject", "<br/>Description", "Hours<br/>Preparation", "Hours<br/>Presentation", "Hours<br/>Semester", "Hours<br/>Quarter", "Hours<br/>Earned", "<br/>Price", "<br/>Link"],
stretchH: 'all',
maxRows: 25,
minRows: 25,
minSpareRows: 1,
contextMenu: true,
contextMenuCopyPaste: {
swfPath: "assets/ZeroClipboard.swf"
},
onSelection: function (row, col, row2, col2) {
var meta = this.getCellMeta(row2, col2);
if (meta.readOnly) {
this.updateSettings({fillHandle: false});
}
else {
this.updateSettings({fillHandle: true});
}
},
cells: function (row, col, prop) {
var cellProperties = {};
if (row === 26 || this.instance.getData()[row][col] === 'readOnly') {
cellProperties.readOnly = true; //make cell read-only if it is first row or the text reads 'readOnly'
}
else {
cellProperties.renderer = "negativeValueRenderer"; //uses lookup map
}
return cellProperties;
},
columns: [
{data: "course_id", type: 'text', renderer: safeHtmlRenderer},
//'text' is default, you don't actually have to declare it
{data: "class_date", type: 'date', renderer: safeHtmlRenderer},
{data: "sponsor_name", type: 'text', renderer: safeHtmlRenderer},
{data: "title", type: 'text', renderer: safeHtmlRenderer},
{data: "subject", type: 'text', renderer: safeHtmlRenderer},
{data: "description", type: 'text', renderer: safeHtmlRenderer},
{data: "hours_preparation", type: 'numeric', renderer: safeHtmlRenderer},
{data: "hours_presentation", type: 'numeric', renderer: safeHtmlRenderer},
{data: "hours_semester", type: 'numeric', renderer: safeHtmlRenderer},
{data: "hours_quarter", type: 'numeric', renderer: safeHtmlRenderer},
{data: "hours_earned", type: 'numeric', renderer: safeHtmlRenderer},
{data: "price", type: 'numeric', renderer: safeHtmlRenderer},
{data: "link", type: 'text', renderer: safeHtmlRenderer}
]
});
I think what you want is the standard way of setting placeholders which is the following:
If you look in HOT documentation, you will see that for advanced tasks like yours, setting the columns
option is important. This is an array of objects where each object is a column with its properties. In your case, you'd want to set the property placeholder
to the string that you'd like, or to a function that will calculate it based on whatever you decide is needed.
Below is an example where I've set different placeholders for each column.