Hi I was wondering if anyone knows if it's possible to define a column in slickgrid as being a drop down select list. If not does anyone with some experience with slickgrid know how I should go about adding this option?
Thanks
You probably dont want to make a new select editor for each range of options. Also you may not know that range of all option value beforehand.
In that case you want a flexible range of options in a select type editor. In order to do this you can add an extra option to your column definitions (e.g. called options) like this:
var columns = [
{id:"color", name:"Color", field:"color", options: "Red,Green,Blue,Black,White", editor: SelectCellEditor},
{id:"lock", name:"Lock", field:"lock", options: "Locked,Unlocked", editor: SelectCellEditor}
]
and access that using args.column.options in the init method of your own SelectEditor object like this:
SelectCellEditor : function(args) {
var $select;
var defaultValue;
var scope = this;
this.init = function() {
if(args.column.options){
opt_values = args.column.options.split(',');
}else{
opt_values ="yes,no".split(',');
}
option_str = ""
for( i in opt_values ){
v = opt_values[i];
option_str += "<OPTION value='"+v+"'>"+v+"</OPTION>";
}
$select = $("<SELECT tabIndex='0' class='editor-select'>"+ option_str +"</SELECT>");
$select.appendTo(args.container);
$select.focus();
};
this.destroy = function() {
$select.remove();
};
this.focus = function() {
$select.focus();
};
this.loadValue = function(item) {
defaultValue = item[args.column.field];
$select.val(defaultValue);
};
this.serializeValue = function() {
if(args.column.options){
return $select.val();
}else{
return ($select.val() == "yes");
}
};
this.applyValue = function(item,state) {
item[args.column.field] = state;
};
this.isValueChanged = function() {
return ($select.val() != defaultValue);
};
this.validate = function() {
return {
valid: true,
msg: null
};
};
this.init();
}
I assume you mean a custom cell editor.
Here's a sample select-based boolean cell editor from slick.editors.js. You could easily modify it to work with an arbitrary set of possible values.
function YesNoSelectCellEditor($container, columnDef, value, dataContext) {
var $select;
var defaultValue = value;
var scope = this;
this.init = function() {
$select = $("<SELECT tabIndex='0' class='editor-yesno'><OPTION value='yes'>Yes</OPTION><OPTION value='no'>No</OPTION></SELECT>");
if (defaultValue)
$select.val('yes');
else
$select.val('no');
$select.appendTo($container);
$select.focus();
};
this.destroy = function() {
$select.remove();
};
this.focus = function() {
$select.focus();
};
this.setValue = function(value) {
$select.val(value);
defaultValue = value;
};
this.getValue = function() {
return ($select.val() == 'yes');
};
this.isValueChanged = function() {
return ($select.val() != defaultValue);
};
this.validate = function() {
return {
valid: true,
msg: null
};
};
this.init();
};
If your cell already contains a "select"-tag with multiple options, you can extract this html from the args. The approach differs from the previous answers, but I was personally troubled with these solutions, course my cell already contained a select-tag. I'd like to reuse this cell instead of reconstructing it completely in the this.init. Likewise, I'd like to keep using the same options, as my existing select already have, instead of parsing them to the var column = { ...
The $( args.item[ args.column.field ] ) return the active cells content, which basically just get re-appended to the the container (the cell-object). From if ( document.createEvent ) and down, is just a functionality which automatically opens the dropdown on activation; etc. when you use tabulator to navigate to the cell.
function SelectCellEditor( args ) {
var $select;
var defaultValue;
var scope = this;
this.init = function () {
$select = $( args.item[ args.column.field ] );
$select.appendTo( args.container );
$select.focus();
// Force the select to open upon user-activation
var element = $select[ 0 ];
if ( document.createEvent ) { // all browsers
var e = new MouseEvent( "mousedown", {
bubbles: true,
cancelable: true,
view: window
});
element.dispatchEvent( e );
} else if ( element.fireEvent ) { // ie
element.fireEvent( "onmousedown" );
}
};
}
Complet editor for Dropdown html-input -> Dropdown html-output
function SelectCellEditor( args ) {
var $select = $( args.item[ args.column.field ] );
var defaultValue;
var scope = this;
this.init = function () {
//$select
$select.appendTo( args.container );
// Force the select to open upon user-activation
var element = $select[ 0 ];
if ( document.createEvent ) { // all browsers
var e = new MouseEvent( "mousedown", {
bubbles: true,
cancelable: true,
view: window
});
element.dispatchEvent( e );
} else if ( element.fireEvent ) { // ie
element.fireEvent( "onmousedown" );
}
$select.on("click", function( e ) {
var selected = $( e.target ).val();
$select.find( "option" ).removeAttr( "selected" );
$select.find( "option[value='" + selected + "']" ).attr( "selected", "selected" );
});
};
this.destroy = function () {
$select.remove();
};
this.focus = function () { };
this.loadValue = function ( item ) { };
this.serializeValue = function () { };
// Only runs if isValueChanged returns true
this.applyValue = function ( item, state ) {
item[ args.column.field ] = $select[ 0 ].outerHTML;
};
this.isValueChanged = function () {
return true;
};
this.validate = function () {
return {
valid: true,
msg: null
};
};
this.init();
}
Without jq, and inline injected elements, packed in module:
'use strict';
class SelectCellWidget {
constructor(args) {
this._args = args;
this._$select = undefined;
this._defaultValue = undefined;
this._init();
}
_init () {
let selects, container, divend, opt_values;
const args = this._args;
if(args.column.options){
opt_values = args.column.options.split(',');
}else{
opt_values = ["yes","no"];
}
container = document.createElement("div");
container.classList.add('select-editable');
divend = document.createElement('input');
divend.setAttribute("type", "text");
divend.setAttribute("name", "format");
divend.setAttribute("value", "");
selects = document.createElement("select");//"<select id='Mobility' tabIndex='0' class='editor-select'>"+ option_str +"</select>";
selects.setAttribute("id", "Mobility");
selects.setAttribute("tabIndex", 0);
selects.setAttribute("class", "editor-select");
for(let i = 0; i < opt_values.length; i++) {
let v = opt_values[i];
let option = document.createElement("option");
option.setAttribute("value", v);
option.innerText = v;
selects.appendChild(option);
}
container.appendChild(divend);
container.appendChild(selects);
this._$select = container;
args.container[0].appendChild(this._$select);
this._$select.focus();
document.getElementById("Mobility").selectedIndex = args.item[args.column.field] ? opt_values.indexOf(args.item[args.column.field]) : 0;
}
destroy () {
this._$select.remove();
}
focus () {
this._$select.focus();
}
loadValue (item) {
this._defaultValue = item[this._args.column.field];
this._$select.value = this._defaultValue;
}
serializeValue () {
if(this._args.column.options){
return this._$select.lastElementChild.value;
}else{
return (this._$select.lastElementChild.value === "yes");
}
}
applyValue (item,state) {
item[this._args.column.field] = state;
}
isValueChanged () {
return (this._$select.lastElementChild.value !== this._defaultValue);
}
validate () {
return {
valid: true,
msg: null
};
}
}
module.exports=SelectCellWidget;
https://github.com/YaAlfred/SlickgridSelectDropdownWidget
Related
I installed Shuffle.js from a codepen demo with some customizations to style and figure cards. I've added in recommended js code but the shuffle function doesn't seem work.
Getting several errors:
console errors
I've tried updating script based on some past answers to this problem. I've also downloaded and added the actual js file on my site and referenced it in the script. Here's what my script looks like right now:
<script src="/v/vspfiles/assets/js/shuffle.js"></script>
<script>
'use strict';
var Shuffle = window.shuffle;
var Demo = function (element) {
this.element = element;
// Log out events.
this.addShuffleEventListeners();
this.shuffle = new Shuffle(element, {
itemSelector: '.picture-item',
sizer: element.querySelector('.my-sizer-element'),
});
this._activeFilters = [];
this.addFilterButtons();
this.addSorting();
this.addSearchFilter();
this.mode = 'exclusive';
};
Demo.prototype.toArray = function (arrayLike) {
return Array.prototype.slice.call(arrayLike);
};
Demo.prototype.toggleMode = function () {
if (this.mode === 'additive') {
this.mode = 'exclusive';
} else {
this.mode = 'additive';
}
};
/**
* Shuffle uses the CustomEvent constructor to dispatch events. You can listen
* for them like you normally would (with jQuery for example). The extra event
* data is in the `detail` property.
*/
Demo.prototype.addShuffleEventListeners = function () {
var handler = function (event) {
console.log('type: %s', event.type, 'detail:', event.detail);
};
this.element.addEventListener(Shuffle.EventType.LAYOUT, handler, false);
this.element.addEventListener(Shuffle.EventType.REMOVED, handler, false);
};
Demo.prototype.addFilterButtons = function () {
var options = document.querySelector('.filter-options');
if (!options) {
return;
}
var filterButtons = this.toArray(
options.children
);
filterButtons.forEach(function (button) {
button.addEventListener('click', this._handleFilterClick.bind(this), false);
}, this);
};
Demo.prototype._handleFilterClick = function (evt) {
var btn = evt.currentTarget;
var isActive = btn.classList.contains('active');
var btnGroup = btn.getAttribute('data-group');
// You don't need _both_ of these modes. This is only for the demo.
// For this custom 'additive' mode in the demo, clicking on filter buttons
// doesn't remove any other filters.
if (this.mode === 'additive') {
// If this button is already active, remove it from the list of filters.
if (isActive) {
this._activeFilters.splice(this._activeFilters.indexOf(btnGroup));
} else {
this._activeFilters.push(btnGroup);
}
btn.classList.toggle('active');
// Filter elements
this.shuffle.filter(this._activeFilters);
// 'exclusive' mode lets only one filter button be active at a time.
} else {
this._removeActiveClassFromChildren(btn.parentNode);
var filterGroup;
if (isActive) {
btn.classList.remove('active');
filterGroup = Shuffle.ALL_ITEMS;
} else {
btn.classList.add('active');
filterGroup = btnGroup;
}
this.shuffle.filter(filterGroup);
}
};
Demo.prototype._removeActiveClassFromChildren = function (parent) {
var children = parent.children;
for (var i = children.length - 1; i >= 0; i--) {
children[i].classList.remove('active');
}
};
Demo.prototype.addSorting = function () {
var menu = document.querySelector('.sort-options');
if (!menu) {
return;
}
menu.addEventListener('change', this._handleSortChange.bind(this));
};
Demo.prototype._handleSortChange = function (evt) {
var value = evt.target.value;
var options = {};
function sortByDate(element) {
return element.getAttribute('data-created');
}
function sortByTitle(element) {
return element.getAttribute('data-title').toLowerCase();
}
if (value === 'date-created') {
options = {
reverse: true,
by: sortByDate,
};
} else if (value === 'title') {
options = {
by: sortByTitle,
};
}
this.shuffle.sort(options);
};
// Advanced filtering
Demo.prototype.addSearchFilter = function () {
var searchInput = document.querySelector('.js-shuffle-search');
if (!searchInput) {
return;
}
searchInput.addEventListener('keyup', this._handleSearchKeyup.bind(this));
};
/**
* Filter the shuffle instance by items with a title that matches the search input.
* #param {Event} evt Event object.
*/
Demo.prototype._handleSearchKeyup = function (evt) {
var searchText = evt.target.value.toLowerCase();
this.shuffle.filter(function (element, shuffle) {
// If there is a current filter applied, ignore elements that don't match it.
if (shuffle.group !== Shuffle.ALL_ITEMS) {
// Get the item's groups.
var groups = JSON.parse(element.getAttribute('data-groups'));
var isElementInCurrentGroup = groups.indexOf(shuffle.group) !== -1;
// Only search elements in the current group
if (!isElementInCurrentGroup) {
return false;
}
}
var titleElement = element.querySelector('.picture-item__title');
var titleText = titleElement.textContent.toLowerCase().trim();
return titleText.indexOf(searchText) !== -1;
});
};
document.addEventListener('DOMContentLoaded', function () {
window.demo = new Demo(document.getElementById('grid'));
});
</script>
Any insight into what I need to remedy to get this working properly would be great. Thanks!
I use a plugin so when I click on a table row it goes to that url. Now this works fine but I would like it to open as a new tab. I know that " window.open('urlhere','_blank');" opens the url into a new tab but I cant figure out where I should put it. Does anyone know how or has experience with this plugin?
Plugin I use : https://github.com/DeOldSax/clickable-tr-jquery
Plugin code:
(function ( $ ) {
var disableClickClass = 'disable-row-click';
var defaults = {};
var settings;
$.fn.clickableTable = function( options ) {
settings = $.extend( defaults, options);
var rows = this.find('tr[data-href], tr[data-event]');
rows.css("cursor", "pointer");
rows.find("td." + disableClickClass).css("cursor", "default");
addClickEvent(rows);
return this;
};
function addClickEvent(rows) {
rows.click(function(e) {
if (notClickable(e)) {
return;
}
var dataEvent = $(this).data("event");
if ( dataEvent ) {
if (settings && settings[dataEvent]) {
settings[dataEvent].call( this, e );
} else {
var fun = window[dataEvent];
if ( typeof fun === "function" ) {
fun.call( this, e );
}
}
}
var dataHref = $(this).data("href");
if ( dataHref ) {
var isRemote = $(this).data("remote");
var id = "uniquy-id-id";
var aTag = buildATag(id, dataHref, isRemote);
document.getElementById(id).click();
aTag.remove();
}
});
}
function notClickable(e) {
var target = $(e.target);
return e.target.localName == 'a' ||
e.target.localName == 'button' ||
target.hasClass(disableClickClass) ||
target.closest('td').hasClass(disableClickClass);
}
function buildATag(id, dataHref, isRemote) {
var a = $('<a></a>');
a.css('display', 'none');
a.attr('data-remote', isRemote);
a.attr('href', dataHref);
a.attr('id', id);
a.insertAfter($("body"));
return a;
}
}( jQuery ));
Just use this code: jsFiddle
$("tr").click(function(){
var $href = $(this).data("href");
window.open($href,'_blank');
});
Exclude the last td Element: jsFiddle
$("tr").click(function(){
var $href = $(this).data("href");
window.open($href,'_blank');
});
$("tr > td:last-child").click(function(event){
event.stopPropagation();
});
Hey all I am using flexslider in my website for slider the slider is running fine on my server at http://www.reurl.in/31830875a but when checked on local server or made life somewhere else I am getting this error in console "Cannot read property 'wrapup' of undefined" and slider is not working
Here is the function
function FlexsliderManualDirectionControls( element, options ) {
this.element = element;
this.options = $.extend( {}, defaults, options) ;
this._flexslider = $(element).data('flexslider');
this._originalFlexsliderWrapupFunction = this._flexslider.wrapup;
this._defaults = defaults;
this._name = flexsliderManualDirectionControls;
this.init();
}
This is just a single function out of full page code.
the console says error at this._originalFlexsliderWrapupFunction = this._flexslider.wrapup;
If you find something helpful please do reply back.
Incase you need full code
/*jshint bitwise:true, curly:true, eqeqeq:true, forin:true, immed:false, latedef:true, newcap:true, noarg:true, noempty:true, nonew:true, undef:true, strict:false, trailing:true, browser:true, jquery:true */
/*!
* jQuery flexslider extension
* Original author: #markirby
* Licensed under the MIT license
*/
(function ( $, window, document, undefined ) {
var flexsliderManualDirectionControls = 'flexsliderManualDirectionControls',
defaults = {
previousElementSelector: ".previous",
nextElementSelector: ".next",
disabledStateClassName: "disable"
};
function FlexsliderManualDirectionControls( element, options ) {
this.element = element;
this.options = $.extend( {}, defaults, options);
this._flexslider = $(element).data('flexslider');
this._originalFlexsliderWrapupFunction = this._flexslider.wrapup;
this._defaults = defaults;
this._name = flexsliderManualDirectionControls;
this.init();
}
FlexsliderManualDirectionControls.prototype.init = function () {
this.addEventListeners();
var self = this;
this._flexslider.wrapup = function(direction) {
self.onAnimationEnd.call(self, direction);
};
};
FlexsliderManualDirectionControls.prototype.addEventListeners = function() {
$(this.element).find(this.options.previousElementSelector).bind('touchstart.flexsliderPromo click.flexsliderPromo', {self:this}, function(event) {
event.stopPropagation();
event.preventDefault();
if (!event.handled) {
event.data.self.goToTargetInDirection('prev');
event.handled = true;
}
});
$(this.element).find(this.options.nextElementSelector).bind('click.flexsliderPromo', {self:this}, function(event) {
event.stopPropagation();
event.preventDefault();
if (!event.handled) {
event.data.self.goToTargetInDirection('next');
event.handled = true;
}
});
};
FlexsliderManualDirectionControls.prototype.goToTargetInDirection = function(direction) {
var target = this._flexslider.getTarget(direction);
if (this._flexslider.canAdvance(target)) {
this._flexslider.flexAnimate(target);
}
return false;
};
FlexsliderManualDirectionControls.prototype.addOrRemoveDisabledStateForDirection = function(direction, $navElement) {
var target = this._flexslider.getTarget(direction);
if (!this._flexslider.canAdvance(target)) {
$navElement.addClass(this.options.disabledStateClassName);
} else {
$navElement.removeClass(this.options.disabledStateClassName);
}
};
FlexsliderManualDirectionControls.prototype.onAnimationEnd = function(direction) {
var $nextElement = $(this.element).find(this.options.nextElementSelector),
$previousElement = $(this.element).find(this.options.previousElementSelector);
this.addOrRemoveDisabledStateForDirection('next', $nextElement);
this.addOrRemoveDisabledStateForDirection('prev', $previousElement);
this._originalFlexsliderWrapupFunction(direction);
};
$.fn[flexsliderManualDirectionControls] = function ( options ) {
return this.each(function () {
if (!$.data(this, 'plugin_' + flexsliderManualDirectionControls)) {
$.data(this, 'plugin_' + flexsliderManualDirectionControls,
new FlexsliderManualDirectionControls( this, options ));
}
});
};
})( jQuery, window, document );
please, could somebody tell me, what he heck I am doing wrong in my syntax?
The problem starts in the statement this.form.onsubmit, where I get this.initData is not a function.
Thanks.
var Contact_Form = function(element){
this.form = element;
this.errors = new Array();
this.invalid = new Array();
this.inSent = false;
this.name = new String();
this.email = new String();
this.message = new String();
this.initData = function()
{
this.name = this.getElementValue('contact-name');
this.email = this.getElementValue('contact-email');
this.message = this.getElementValue('contact-message');
}
this.form.onsubmit = function(event)
{
event.preventDefault();
this.initData();
if(this.verifyData())
this.send();
}
this.verifyData = function()
{
if(!this.isNameLength())
this.setError('name', 'Zadejte, prosím, jméno dlouhé maximálně 30 znaků.');
if(this.isProperEmail())
{
if(!this.isEmailLength())
this.setError('email', 'Váš e-mail smí obsahovat maximálně 50 znaků.');
}
else
this.setError('email', 'Zadejte, prosím, email v korektním formátu.');
if(!this.isMessageLength())
this.setError('name', 'Zadejte, prosím, zprávu v rozsahu 1-999 znaků.');
this.doInvalidFields();
if(0 == this.errors.length)
return true;
return false;
}
this.doInvalidFields = function()
{
if(this.invalid.length > 0)
{
for(var invalid in this.invalid)
this.getElement(invalid).setAttribute('aria-invalid', true);
}
}
this.setError = function(field, message)
{
this.errors.push(message);
this.invalid.push(field);
}
this.getElementValue = function(element) {
return this.getElement(element).value;
}
this.getElement = function(element) {
return document.getElementById(element);
}
this.getElementName = function() {
return this.getElement('contact-name');
}
this.getElementEmail = function() {
return this.getElement('contact-email');
}
this.getElementMessage = function() {
return this.getElement('contact-message');
}
this.isNameLength = function(){
return this.isLength(this.name, 1, 30);
}
this.isEmailLength = function(){
return this.isLength(this.email, 1, 50);
}
this.isMessageLength = function(){
return this.isLength(this.email, 1, 999);
}
this.isProperEmail = function() {
return this.email.match(/^(?:\w){1,100}#{1}(?:\w){1,100}(?:.){1}(?:\w){1,10}$/ig);
}
this.isLength = function isLength(string, _min, _max) {
if(string.length >= _min && string.length <= _max)
return true;
return false;
}
}
window.onload = function()
{
new Contact_Form(document.forms[0]);
}
The problem is that this is not inherited, and has a different value inside each function.
Then, use
var Contact_Form = function(element){
/* ... */
var that = this;
/* Here this===that */
this.form.onsubmit = function(event)
{
/* Here this===that.form */
event.preventDefault();
that.initData();
if(that.verifyData())
this.send();
}
/* ... */
}
this is referring to the form in the onsubmit handler. You could assign this to a local variable, or bind the handler to the correct this with Function.prototype.bind, ie:
this.form.onsubmit = function(event) {
event.preventDefault();
this.initData();
if(this.verifyData())
this.send();
}.bind(this)
or with jQuery.proxy
this.form.onsubmit = $.proxy(function(event) {
event.preventDefault();
this.initData();
if(this.verifyData())
this.send();
}, this);
Both examples are forcing the this context of the function to be the instance of a Contact_Form whenever the handler is called
Folks, can you please help me with this questions.
var Module = function ( options ) {
var settings = {
selector: 'body',
declaration: function () {
return{
init: function () {
console.log( 'nodule initialize' );
},
destroy: function () {
console.log( ' module destroyed' );
}
}
}
};
this.declaration = options.declaration || settings.declaration;
this.selector = options.selector || settings.selector;
};
var Registration = function ( options ) {
this.selector = options.selector || **strong text**;
this.declaration = options.declaration
}
app.utils.extend( Module, Registration );
var m_registration = new Registration( {
declaration: function ( f ) {
return {
init: function () {
},
destroy: function () {
}
}
}
} );
My main questions, how i can inherit Module.selector properties in m_registration, if we haven't need quantity arguments passed when we are creating instance of Registration
My realisation of function app.utils.extend():
var app.utils.extend = function ( from, to ) {
var F = function () {
};
F.prototype = from.prototype;
to.prototype = new F();
to.prototype.constructor = to;
to.superclass = from.prototype;
}
Update:
If we are using these method:
var Registration = function ( options ) {
Module.call(this, { selector : options.selector });
this.declaration = options.declaration
}
How we can use inheritance if we really dont know from what instance this class extended or inheritance.
var Registration = function ( options ) {
Module.call(this, { selector : options.selector || **strong text**});
this.declaration = options.declaration
}
I don't know what **strong text** means in your case. But if you call it like this
var Registration = function ( options ) {
Module.call(this, { selector : options.selector });
this.declaration = options.declaration
}
Or
var Registration = function ( options ) {
Module.call(this, options );
this.declaration = options.declaration
}
In your case m_registration.selector will be 'body'
var Module = function ( options ) {
this.declaration = options.declaration;
this.selector = options.selector;
}
Module.prototype = {
selector: 'body',
declaration: function () {
return{
init: function () {
console.log( 'nodule initialize' );
},
destroy: function () {
console.log( ' module destroyed' );
}
}
}
};
Another approach is to put all the properties you want inherited to the prototype property. This is how javascript engine deals with inheritance