I am trying to learn JavaScript and I came across a practice problem in a book I purchased that I cannot seem to crack. The task is to flesh out a javascript formBuilder function to generate HTML forms dynamically from a JavaScript array. I have copied the code from the book onto a CodePen page for visual and testing purposes.
CodePen: http://codepen.io/anon/pen/gpwZMX
HTML sample:
<div>
<button data-sample='1'>Run 1</button>
<button data-sample='2'>Run 2</button>
<button data-sample='3'>Run 3</button>
</div>
<hr>
<div id='spec'>
<i>This div will display the currently-processed spec</i>
</div>
<br>Output:
<div id='result'>
<i>I sure wish I had a cool html form in me...</i>
</div>
<!--here are some test cases in docblock form-->
<div class='testcase' id='1'>
/** Comment Form
* Make a comment on the blog post!
* #param string[100] title
* #param email email
* #param text body
* #param bool subscribe Email me when someone comments on my comment!
*/
</div>
JavaScript sample:
var samples = [
{
title:"Comment Form",
desc:"Make a comment on the blog post!",
params:[
{
type: 'text',
max_length: 100,
name: 'title'
},
{
type: 'email',
name: 'email'
},
{
type:'textarea',
name:'body'
},
{
type:'checkbox',
name:'subscribe',
label:'mail me when someone comments on my comment!'
}
]
}]
formBuilder sample:
//builds an HTML form using all information present in `spec` and places the resulting HTML in jquery element `$el`
function formBuilder(spec,$el){
$el.html("<i>I still wish I had a cool html form in me...</i>");
}
$("button").on("click",function($e){
var specIndex = $($e.target).data('sample');
var specData = samples[specIndex-1];
$("#spec").html("Sample spec "+(specIndex)+" looks like: <br>"+JSON.stringify(specData));
formBuilder(specData, $("#result"));
});
Errors in the codepen code exist, paste the code below into your project:
var samples = [
{
title:"Comment Form",
desc:"Make a comment on the blog post!",
params:[
{
type: 'text',
max_length: 100,
name: 'title'
},
{
type: 'email',
name: 'email'
},
{
type:'textarea',
name:'body'
},
{
type:'checkbox',
name:'subscribe',
label:'mail me when someone comments on my comment!'
}
]
},
{
title:"Car Order Form",
desc:"Choose your car!",
params:[
{
type:'select',
values:['red','blue','green','black','white','taupe'],
name: 'color'
},
{
type: 'checkbox',
values:['fog-lights','radio','a-c','wheels','headlights'],
name: 'options'
},
{
type:'string',
minLength:7,
maxLength:7,
name:'vanityPlate',
optional:true
},
{
type:'int',
name:'price',
}
]
},
{
title:"New User Creator",
desc:"Create a new user account",
params:[
{
type:'string',
maxLength:20,
name:'fname',
label:'First Name'
},
{
type:'string',
maxLength:20,
name:'lname',
label:'Last Name'
},
{
type:'date',
name:'dob',
label:'Date of Birth'
},
{
type:'email',
multiple:true,
maxCount:4,
name:'emails',
label:'Email Addresses'
},
{
type: 'string',
name: 'addr1',
label: 'Street Address'
},
{
type: 'string',
name: 'city'
},
{
type: 'state',
name: 'state',
},
{
type: 'int',
name: 'zipcode',
maxValue: 99999,
minValue: 0,
label: 'ZIP'
},
]
}
]
//builds an HTML form using all information present in `spec` and places the resulting HTML in jquery element `$el`
function formBuilder(spec,$el){
var inputs = getInputs(spec);
$el.html("<form title='"+spec.title+"'><fieldset><legend>"+spec.desc+"</legend>"+inputs+"</fieldset></form>");
}
function getInputs(spec) {
var inputs = "";
for(var i = 0; i < spec.params.length; i++) {
var input = "<input ";
var attributes = JSON.stringify(spec.params[i]).split(",");
console.log(attributes);
for(var j = 0; j < attributes.length; j++) {
$.each(spec.params[i], function(key, value) {
input += key + "='" + value + "' ";
});
}
inputs += input + "/><br/>";
}
return inputs;
}
$("button").on("click",function($e){
var specIndex = $($e.target).data('sample');
var specData = samples[specIndex-1];
$("#spec").html("Sample spec "+(specIndex)+" looks like: <br>"+JSON.stringify(specData));
formBuilder(specData, $("#result"));
});
The last item in an array does not get a comma appended to it. Always ensure to end a line of code with a semi-colon as well. Those are the changes I made to your code, now it runs, as I assume, correctly unless you have any other issues?
Related
Following the example here, we've been trying for over a week to get Tabulator working with a Select2 header filter. There is a JS Fiddle here with all the pieces. It seems like the Tabulator filter (which are really just editors) onRendered() function is not even getting called because the console log we have inside it never gets logged.
The select element itself shows up in the header filter, but never gets the Select2 object applied (probably because the onRendered seems to not even be called). If we put the Select2 object outside the onRendered function, it get applied, but then the filter does not get applied after selection is made. There are no console or other errors and we've followed the Tabulator 'example' to the letter, so we are not sure what to try next.
Does anyone know how to get a basic Select2 header filter functioning with Tabulator?
var tableData = [{
id: "1",
topic: "1.1"
},
{
id: "2",
topic: "2.2"
},
];
var select2Editor = function(cell, onRendered, success, cancel, editorParams) {
var editor = document.createElement("select");
var selData = [{
id: '1.1',
text: "One"
}, {
id: "2.2",
text: "Two"
}, {
id: "3.3",
text: "Three"
}, ];
onRendered(function() {
// TODO: map tracks to id and text
console.log('rendered');
$(editor).select2({
data: selData,
minimumResultsForSearch: Infinity,
width: '100%',
minimumInputLength: 0,
//allowClear: true,
});
$(editor).on('change', function(e) {
success($(editor).val());
});
$(editor).on('blur', function(e) {
cancel();
});
});
return editor
};
var columns = [{
title: "ID",
field: "id"
}, {
title: "Topic",
field: "topic",
headerFilter: select2Editor,
}, ];
var table = new Tabulator("#table", {
placeholder: "No Data Found.",
layout: "fitData",
data: tableData,
columns: columns,
});
I'm new to both Tabulator and select2 and I think this is possibly a bad way to do it but it seems like it miiight work.
If you want to use select2 with text input elements, it looks like you need to use the full package.
https://jsfiddle.net/dku41pjy/
var tableData = [{
id: "1",
topic: "1.1"
},
{
id: "2",
topic: "2.2"
},
];
var columns = [{
title: "ID",
field: "id"
}, {
title: "Topic",
field: "topic",
headerFilter: 'select2Editor'
}, ];
var awaiting_render = [];
function do_render({ editor, cell, success, cancel, editorParams }) {
console.log('possibly dodgy onrender');
var selData = [{
id: '',
text: "-- All Topics --"
}, {
id: '1.1',
text: "One"
}, {
id: "2.2",
text: "Two"
}, {
id: "3.3",
text: "Three"
}, ];
$(editor).select2({
data: selData,
//allowClear: true,
});
$(editor).on('change', function(e) {
console.log('chaaaange')
success($(editor).val());
});
$(editor).on('blur', function(e) {
cancel();
});
}
function render_awaiting() {
var to_render = awaiting_render.shift();
do_render(to_render);
if(awaiting_render.length > 0)
render_awaiting();
}
Tabulator.prototype.extendModule("edit", "editors", {
select2Editor:function(cell, onRendered, success, cancel, editorParams) {
console.log(cell);
var editor = document.createElement("input");
editor.type = 'text';
awaiting_render.push({ editor, cell, success, cancel, editorParams });
return editor
},
});
var table = new Tabulator("#table", {
placeholder: "No Data Found.",
layout: "fitData",
data: tableData,
columns: columns,
tableBuilt:function(){
render_awaiting();
},
});
Edit: my suspicion is that onRendered only gets fired when these edit elements are used in cells to sope with the transition between showing just data and showing an editable field.
Hi everybody this is my first project in meteor js.
I'm using Meteor 1.4.1.1 with this package:
aldeed:collection2 2.10.0
I have this field in my collection
Clienti.ClienteSchema = new SimpleSchema({
cantieri: {
type: [Clienti.Cantieri],
optional: true,
autoform: {
type: "hidden"
}
}
});
Clienti.Cantieri = new SimpleSchema({
giorni: {
type: [Clienti.Giorni],
optional: true,
autoform: {
type: "hidden"
}
}
});
Clienti.Giorni = new SimpleSchema({
giorno: {
type: Date,
label: "giorno del lavoro"
},
oraPartenza: {
type: Date,
label: 'Giorno e ora partenza',
},
oraInizio: {
type: Date,
label: 'Giorno e ora inizio',
optional: true
},
oraFine: {
type: Date,
label: 'Giorno e ora fine',
optional: true
},
dipendenti: {
type: [Dipendenti]
}
});
This is the input's select
<div class="col-xs-12">
<div class="form-group">
<label class="checkbox" for=dipendenti>dipendenti</label>
<select multiple name="dipendenti">
{{#each Dipendenti}}
<option value="{{_id}}">{{nome}} {{cognome}}</option>
{{/each}}
</select>
</div>
</div>
with this form I'd like to submit the last field Giorni in a existing Cliente.cantiere.
I tried:
Template.nuovoGiorno.events({
'submit #Giorno'(event) {
event.preventDefault();
const id = FlowRouter.getParam('id');
const target = event.target;
const giorno = target.giorno.value;
const oraPartenza = target.oraPartenza.value;
let select = target.dipendenti.options;
let selezionati=[];
for (var i = 0; i < select.length; i++) {
var option = select[i];
if (option.selected){
console.log(id);
console.log('opzione ' + option.value);
Clienti.update({_id:id}, {$set:{
'cantieri.giorni.giorno': giorno,
'cantieri.giorni.oraPartenza': oraPartenza,
'cantieri.giorni.dipendenti._id': option.value
}});
}
}
}
});
but doesn't work. How can I fix it?
It looks like your cantieri key is an array of objects which are themselves arrays of objects. Is this really what you want?
I would try:
Clienti.update({ _id: id }, { $set: {
cantieri: [{
giorni: [{
giorno: giorno,
oraPartenza: oraPartenza,
dipendenti._id: option.value
}]
}]
}});
If you want to push a giorni into a specific cantieri (as per your comment) then select the cantieri you want in the query and then push a new giorni into it:
Clienti.update({ _id: id, cantieri: myCantieri }, { $push: { 'cantieri.giorni': newGiorni }});
In my Dgrid I have a column that displays the code (in number format) for an event.
enter image description here
I want to display the label not the number in the dgrid. So if 1 = Cat. In the database it shows as a 1 - but I want to display 'Cat' in dgrid. Can't find anything on how to do this.
Help or a lead in a direction would be helpful. Thanks!!
UPDATED: 6.16.15
Here is the code. I'm limited in what I can show.
These are some of the codes. 02 = XXXXX, 03 = XXXXX1, and so on and so on. Right now, the dgrid displays the numbers. It's kind of like a key. I need it to display what the number represents in the dgrid, not the number. So 02 should display 'Traffic Stop'. Not sure how to do a jsfiddle yet, and don't have a whole lot of extra time at the moment. I'm limited in what info I can give out, so I'd have to recreate a dummy version.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>XXXXXXXX Events</title>
<link rel="stylesheet" href="/static/web_ui/dgrid/css/skins/slate.css">
<h1>XXXXXXXX Events</h1>
<form id="queryForm">
<label for="XXXXXField">XXXXX Type contains:</label>
<input id="XXXXXField" name="event_type">
<button type="submit">Filter</button>
<button type="reset">Reset</button>
</form>
<script src="/static/web_ui/dojo/dojo.js"
data-dojo-config="async: true"></script>
<script>
require([
'dojo/_base/declare',
'dojo/dom',
'dojo/on',
'dstore/Rest',
'dstore/Request',
'dgrid/extensions/ColumnResizer',
'dgrid/extensions/ColumnReorder',
'dgrid/CellSelection',
'dgrid/extensions/DijitRegistry',
// 'dstore/Memory',
// 'dstore/Trackable',
// 'dstore/Cache',
'dgrid/OnDemandGrid'
// 'dojo/domReady!'
], function (declare, dom, on, Rest, Request, ColumnResizer, ColumnReorder, CellSelection, DijitRegistry, OnDemandGrid) {
var store = new Rest({target:'/api/XXXXXXEvents/?format=json',
sortParam: 'ordering', ascendingPrefix:'', descendingPrefix:'-'
});
// var cacheStore = Cache.create(store, {
// cachedStore: new (Memory.createSubclass(Trackable)) ()
// });
var grid = window.grid = new (declare([OnDemandGrid, ColumnResizer, ColumnReorder, CellSelection, DijitRegistry])) ({
collection: store,
selectionMode: 'single',
sort: 'id',
// idProperty: 'id',
columns: [
{field: 'id', label:'ID', resizeable: false},
{field: 'XXXXX_type', label:'XXXXX Type', resizeable: false},
{field: 'XXXXX_at', label:'XXXXX Time', resizeable: false},
{field:'XXXXX', label:'XXXXX Count', resizeable: false},
{field:'XXXXX', label:'XXXXX', resizeable: false},
{field:'XXXXX_info', label:'XXXXX Info', resizeable: false},
{field:'hidden', label:'Hidden', resizeable: false},
{field:'XXXXX', label:'XXXXX', resizeable: false},
{field:'XXXXX', label:'XXXXX', resizeable: false}
]
}, 'grid');
grid.startup();
on(dom.byId('queryForm'), 'submit', function(event) {
event.preventDefault();
grid.set('collection', store.filter({
// Pass a RegExp to Memory's filter method
// Note: this code does not go out of its way to escape
// characters that have special meaning in RegExps
last: new RegExp("^\d+$")
}));
});
on(dom.byId('queryForm'), 'reset', function() {
// Reset the query when the form is reset
grid.set('collection', store);
});
});
</script>
</head>
<body class="slate">
<div id="grid"></div>
</body>
</html>
You need to use the column formatter function for rendering data.
check the jsfiddle over here.
Check the examples over here
I have taken this example and modified as per your needs.
require([
'dgrid/Grid',
'dojo/domReady!'
], function(Grid) {
var data = [
{ id: 1, number: 7 },
{ id: 2, number: 8 },
{ id: 3, number: 9 }
];
function testFormatter(item){
//console.log(item,typeof(item));
var newItem;
if ( item == 7 )
newItem = 'Dog'
else if ( item == 8 )
newItem = 'Cat'
else if ( item == 9 )
newItem = 'Bird'
return newItem;
}
var columnsFormatter = [
{
label: "Number",
field: "number",
formatter: testFormatter
}
];
var grid = new Grid({
columns: columnsFormatter
}, "gridcontainer");;
grid.renderArray(data);
});
I'm facing some issue here when i try to use a dropdown inside a ui-grid passing to it fields from a database. Following the docs, in the gridOptions.columnDefs, i have create an array of id and a value, like:
{ name: 'gender', displayName: 'Gender', editableCellTemplate: 'ui-grid/dropdownEditor', width: '20%',
cellFilter: 'mapGender', editDropdownValueLabel: 'gender', editDropdownOptionsArray: [
{ id: 1, gender: 'male' },
{ id: 2, gender: 'female' }
] },
but, in my case the "id" and the "value", must be fields from the database, as follows:
{ id: data.Id, gender: data.Nome }
It just don't work. Any ideas about how to solve this?
Thanks!!
You could consider using Angular Grid - it allows you to have custom cell renderers, where you can have a cell renderer that's interactive. I have it working in my job (can't post the code example as it belongs to the company I work for) however if this is an option I can mock something up and post it.
Here is my approach. It was based on this thread:
https://github.com/angular-ui/ng-grid/issues/2808
1) I defined an uiGridFactory.js as this one:
angularFactories.factory('uiGridFactory', function ($http, $rootScope) {
var factory = {};
/* It returns a dropdown filter to help you show editDropdownValueLabel
*
* Parameters:
*
* - input: selected input value, it always comes when you select a dropdown value
* - map: Dictionary containing the catalog info. For example:
* $scope.languageCatalog = [ {'id': 'EN', 'description': 'English'}, {'id': 'ES', 'description': 'EspaƱol'} ]
* - idLabel: ID label. For this example: 'id'.
* - valueLabel: Value label. For this example: 'description'.
*
* 1) Configure cellFilter this way at the ui-grid colDef:
*
* { field: 'languageId', name: 'Language'), editableCellTemplate: 'ui-grid/dropdownEditor',
* editDropdownIdLabel: 'id', editDropdownValueLabel: 'description',
* editDropdownOptionsArray: $scope.languageCatalog,
* cellFilter: 'mapDropdown:row:row.grid.appScope.languageCatalog:"id":"description":languageCatalog' },
*
* 2) Append this snippet to the controller:
*
* .filter('mapDropdown', function(uiGridFactory) {
* return uiGridFactory.getMapDrowdownFilter()
* });
*
*/
factory.getMapDrowdownFilter = function() {
return function(input, map, idLabel, valueLabel) {
if (map != null)
{
for (var i = 0; i < map.length; i ++) {
if (map[i][idLabel] == input)
{
return map[i][valueLabel];
}
}
}
return "";
}
}
return factory;
});
2) Then I added the filter mapDropdown at the end of the controller that requires dropdown logic
.filter('mapDropdown', function(uiGridFactory) {
return uiGridFactory.getMapDrowdownFilter()
});
3) I added this cellFilter to the column definition that contains the dropdown:
columnDefs: [
{ field: 'id', 'ID')},
{ field: 'languageId', name: 'Language',
editableCellTemplate: 'ui-grid/dropdownEditor',
editDropdownIdLabel: 'id', editDropdownValueLabel: 'description',
editDropdownOptionsArray: $scope.languageCatalog,
cellFilter: 'mapDropdown:row.grid.appScope.languageCatalog:"id":"description"' },
{ field: 'comments', 'Comments' }
]
where the mapDropdown() parameters are:
a) the catalog map (row.grid.appScope.languageCatalog)
b) the ID label
c) the VALUE label
Note: In my example I used $scope.languageCatalog variable that was loaded from Database with a factory. You have to implement your own.
factory.getLanguages = function (callback) {
$http.get(RESOURCES.REST_ADDRESS + 'getLanguages').
success(function (data, status, headers, config) {
callback(data);
}).
error(function (data, status, headers, config) {
});
}
Try something like this
editableCellTemplate: 'ui-grid/dropdownEditor',
editDropdownOptionsArray: YourDataArray,
editDropdownIdLabel: 'Id',
editDropdownValueLabel: 'Nome'
YourDataArray could be a service call - for example, for me I have a call to MyServiceName.Get() - the objects returned might have properties like 'Id' and 'Nome' as in your question.
I want select2 to behave as sort of combobox.See attached image for ref.
So if user types in a string but it is not found in source array, then on enter or closing select2 it should add that new string to source. So say if there were 2 values before, after above there would be now 3.
select2 just like combobox in file open dialogs
I have created sample code, but cant make it to work.I am unable to update source.
JSFIDDLE:
HTML:
<div class="row">
<div class="col-md-2">
<input type="hidden" id="select2_sample3" class="form-control ">
</div>
</div>
JS:
$(function () {
var preload_data = {
results: [{
id: 'user0',
text: 'Disabled User',
}, {
id: 'user1',
text: 'Jane Doe'
}]
};
$("#select2_sample3").select2({
placeholder: "Select...",
allowClear: true,
minimumInputLength: 1,
data: preload_data,
query: function (query) {
var data = {
results: []
}, i, j, s;
for (i = 1; i < 5; i++) {
s = "";
for (j = 0; j < i; j++) {
s = s + query.term;
}
data.results.push({
id: query.term + i,
text: s
});
}
query.callback(data);
}
}).on("select2-close", function () {
// add to
console.log("close");
});
});
I've recently had the same task. This is my solution:
<input type="hidden" name="trBrand" id="trBrand" class="form-control"></input>
and js code
$('#trBrand').select2({
placeholder: 'choose something',
allowClear: true,
id: function(object) {
return object.text;
},
createSearchChoice:function(term, data) {
if ( $(data).filter( function() {
return this.text.localeCompare(term)===0;
}).length===0) {
return {id:term, text:term};
}
},
data:preload_data
});