This relates to an online clothing store. We have variable products set up with colour and size attributes, for example a product might have 2 variations; Green/Any Size and Black/Any Size.
There is an image of the product in the corresponding colour for each variation, but at the moment the image doesn't switch unless a colour AND size is selected (I'm aware this is how Woo works out of the box). We would like to make it so that the image switches when JUST a colour is selected.
I have come accross this code on SO and another site. It allows a product variation image to change when only the one main attribute is selected (e.g. color), rather than having to select all variation attributes (e.g color and size) in order for the image to change.
This code was written to work with a plugin, however the person who wrote it mentioned changing line 6 in order to use without plugins.
Can someone help me to adjust this code to my ecommerce store? I know that this can be easly done by someone who understand JS, but since I am not a developer it's really hard for me. I hope someone could help!
var image_to_show = '';
var variations = JSON.parse($(".variations_form").attr("data-product_variations"));
if(variations) {
var first_attr = Object.keys(variations[0].attributes)[0];
// when swatch button is clicked
$("ul[data-attribute_name='"+first_attr+"'] li").click(function() {
var choice = $(this).attr("data-value");
var found = false;
// loop variations JSON
for(const i in variations) {
if(found) continue;
if(variations.hasOwnProperty(i)) {
// if first attribute has the same value as has been selected
if (choice === variations[i].attributes[Object.keys(variations[0].attributes)[0]]) {
// change featured image
image_to_show = variations[i].image_src;
found = true;
}
}
}
});
// after woo additional images has changed the image, change it again
jQuery(".variations_form").on("wc_additional_variation_images_frontend_image_swap_done_callback", function() {
if(image_to_show.length) {
$(".attachment-shop_single").attr("src", image_to_show).removeAttr("srcset");
}
});
}
I'd like to create button (or a selectable table) in an rmarkdown file that allows a user to copy a table and paste it into word or excel with some pre-defined formatting.
Is there a way to produce:
A copy function that preserves table formatting, especially borders to cells
A copy function that captures the entirety of a table
Using this very simple dataframe:
data<-data.frame(Variable=c('Amount','Age','Happiness','Favorite Color'),
Value=c(15,25,7,'Yellow'))
I want a user to be able to click a button in the html file such that when they paste into excel or word, they see:
or
depending on the formatting specified.
As it stands, I can make a table that has cell borders with kable,
data%>%
kable("html",align = 'clc')%>%
kable_styling(full_width = F,position="left",bootstrap_options =
c("striped","bordered"))
This table, in the html file generated using rmarkdown, displays cell borders and has acceptable spacing and clarity (columns are wide enough to display full column headers, and the gird clearly defines cells.
When I highlight the table and paste it into Excel, I get:
An unsatisfactory result.
Producing a table with DT, I use:
datatable(data,extensions='Buttons',rownames=FALSE,filter=c("top"),options=list(dom='Bfrtip',buttons=c('csv','copy','excel')))
This produces a table with a CSV, Copy, and Excel button.
The result of using the Copy button and pasting into Excel is:
A user has data that does paste, but lacks any formatting (and puts the title from the file two rows above the datatable itself?)
Is there a way to modify the code for the DT table's Copy button to include some specified formatting, such as a missing argument that gives an option to copy some formatting to clipboard as well? Or a way to produce a standalone button that I can store an excel-formatted table behind so that a user has an way to copy my table in an excel-friendly, formatted form?
Note: I don't want to write to an excel file from R. There seem to be many options for formatting tables and writing to Excel with openxlsx and solutions here: Write from R into template in excel while preserving formatting , but this does not answer my question.
Edit: There seems to be the ability to add the formatting to the Excel button, mentioned here: https://datatables.net/extensions/buttons/examples/html5/excelBorder.html
This gives me hope that perhaps the .attr() specification of the formatting can somehow be added to the copy button.
As a first step in trying to test whether or not I can even get this intermediate step functioning, I tried:
jscode<-"function ( xlsx ){var sheet = xlsx.xl.worksheets['sheet1.xml']; $('row c[r*=10]', sheet).attr( 's', '25' ); }"
datatable(data1,class='cell-border',extensions='Buttons',rownames=FALSE,filter=c("top"),options=list(dom='Blfrtip',buttons=list(list(extend='excel',customize=jscode))))
The result is a spinning-button-of-nothingness.
When I try:
library(jsonlite)
datatable(data1,class='cell-border',extensions='Buttons',rownames=FALSE,filter=c("top"),options=list(dom='Blfrtip',buttons=list(list(extend='excel',customize=fromJSON(jscode)))))
I receive an error:
Since the solution to this question seems to depend on some javascript (at least if the answer will be based on datatable, I've added the javascript tag.
Library kableExtra will help you. Try this:
library(kableExtra)
data %>%
kbl() %>%
kable_paper("hover", full_width = F)
There are other styles, please search Rdocumentation. The table looks like this:
Then I copy:
Finally, paste in Excel:
Some times you need to paste as "Unicode Text" or "Text" (Can do it with special paste).
This code should give you the whole table when copied and removes the table title (without any of the formatting though, maybe somebody can extend this answer):
library(DT)
DT::datatable(mtcars,
filter = 'top',
class = 'cell-border stripe',
extensions = 'Buttons',
options = list(scrollY = 600,
scrollX = TRUE,
dom = 'lBfrtip',
lengthMenu= list(c(10, 25, 100, -1),
c('10', '25', '100','All')),
buttons = list(
list(extend = "copy", text = "copy",
title= "",
exportOptions = list(
modifier = list(page = "all")
)
)
),
scrollCollapse= TRUE,
lengthChange = TRUE,
widthChange= TRUE,
format = list(
header = TRUE
)))
#If you don't want rownames then you can have:
#DT::datatable(mtcars,
# filter = 'top',
# class = 'cell-border stripe',
# extensions = 'Buttons',
# rownames = FALSE,
# extensions = 'Buttons',
# options = list(
# ......)))
When you hit "Copy" and paste it in the excel you should see the following-
Further options related to DT can be found here: https://datatables.net/reference/option/
I found a working solution using javascript in the rmarkdown file, and the kableExtra package for table creation.
In producing the table with kableExtra, you use table.attr to add an ID to the html table that will ultimately be produced like this:
data%>%
kable("html",align = 'clc',table.attr="id=tableofdata")%>%
kable_styling(full_width = F,position="left",bootstrap_options = c("striped","bordered"))%>%
add_header_above(c("Pretty Table"=2))
After the {r} code block, paste
the following script, found here: How to copy table html (data and format) to clipboard using javascript (microsoft edge browser)
<script type="text/javascript">
function selectElementContents(el) {
let body = document.body, range, sel;
if (document.createRange && window.getSelection) {
range = document.createRange();
sel = window.getSelection();
sel.removeAllRanges();
try {
range.selectNodeContents(el);
sel.addRange(range);
} catch (e) {
range.selectNode(el);
sel.addRange(range);
}
} else if (body.createTextRange) {
range = body.createTextRange();
range.moveToElementText(el);
range.select();
}
document.execCommand("Copy");}
</script>
This creates the copy function in javascript. Next, create a button that uses this function to copy the table and the formatting to the clipboard. See that the same term we used as the table.attr ID in the creation of our table needs to be used here within getElementByID to copy the contents.
<button type="button" onclick="selectElementContents( document.getElementById('tableofdata') );">Copy Table</button>
Note:
I found that when I knit my .Rmd file and tried using the button that appears in Rstudio's browser, clicking the button didn't do what I wanted. When I opened the resulting html file Chrome, however, clicking the button copied the table with the formatting successfully. Had I not tried chrome, I may have dismissed this as a non-working solution. I haven't tried opening with different versions of popular browsers.
Once you knit to html, the button will appear under the table, looking something like:
After clicking the button, and pasting in Excel, the borders, bold heading, and title, show up!
Column width doesn't magically keep things looking good in excel, but that's a step for another day.
I have an HTML table for which I have a drop-down, also so that user can see whatever row he wants to see I have an export button. When user clicks on export button I am exporting the data to Excel.
While exporting I am not exporting the hidden row, while applying CSS property display:none I am adding a class there to all the hidden rows and removing them while exporting. But still when I export the data extra two columns are exporting, and I don't know why.
$("#save").on("click", function() {
var selectedType = [];
$.each($(".dropdown-menu input[type='checkbox']:checked"), function() {
selectedType.push($(this).val());
});
$.each($("#salesBreakupTable tr.filterData td:nth-child(2)"), function() {
if (jQuery.inArray($(this).text(), selectedType) == -1 && $(this).text() != "Total") {
$(this).parent().css("display", "none");
$(this).parent().addClass("hide-data"); //class i am adding to hidden rows
} else {
$(this).parent().css("display", "");
$(this).parent().removeClass("hide-data");
}
});
});
$("#export").click(function() { //export button on click
var copyTable = $("#salesBreakupTable").clone(false).attr('id', '_copy_dailySales');
copyTable.insertAfter($("#dailySales"));
copyTable.find('.hide-data').remove(); //removing rows while exporting
copyTable.table2excel({
filename: "Daily Sales Report.xls"
});
copyTable.remove();
});
Link to Fiddle
When I am selecting credit from the drop-down it is exporting like this:
Two columns are extra after the table I have colored the red.
Note
For some reasons I cannot use Data-tables because data-tables is not exporting col-span, it aligns all the columns to left one by one, then data which looks very bad in Excel.
Edit
I just found the reason why it is exporting extra columns, the columns which I am fixing with data-tables are those columns, here I have fixed first two columns so they are exporting extra on excel
Edit
If there is any other approach I am open to that, I have tried Data-tables but it is not exporting columns with col-span, that's why I am using table2export.
Adding this line will do the job for you:
copyTable.find('.DTFC_LeftWrapper').remove(); //removing static columns while exporting
Here is the fiddle with the updated code
How can I add another(two) child(ren) to a responsive datatable.
If the table is too narrow and I click the + button this does nothing
Any thoughts on this?
function format ( d ) {
return '<div class="player"></div>';
}
https://jsfiddle.net/v1xnj3u4/
This seems to work though it doesn't create another row as such but just adds to the created row the div you specified:
"responsive": {
"details": {
"renderer": function ( api, rowIdx ) {
// Select hidden columns for the given row
var data = api.cells(rowIdx, ':hidden').eq(0).map(function(cell){
var header = $(api.column(cell.column).header());
return $("<tr></tr>").append($("<td></td>",{
"text": header.text()+':'
})).append($("<td></td>",{
"text": api.cell( cell ).data()
})).prop('outerHTML');
}).toArray().join('');
return data ?
$('<table/>').append( data ).prop('outerHTML') + $("<div></div>", {"class":"player"}).prop('outerHTML') :
false;
}
}
},
Working example on JSFiddle, thanks for the challenge, I enjoyed learning about that ;-)
You can make (+) icon stay all the time if you make one of the columns hidden, you can create a dummy column for that purpose and use one of the Responsive plugin special classes none as 'className: 'none' for that dummy column.
In the example below I used last column for that purpose because in the row details it will also be displayed last.
Then when enumerating the columns in custom renderer you can display what you want for that column if that special column header matches some predetermined value (I used 'Extra 10' which is the header of the last column).
See this JSFiddle for demonstration.
PS: I used excellent answer and example by #annoyingmouse as a base for this answer so my vote goes to him as well.
Is there any way to do that?
I use jqGrid form editing feature to populate my grid. But jqGrid only permits to add a row on top or bottom position inside the grid. What I want to do is be able to previously select the desired position on the grid (by clicking in any existing row) and then add a row above or below that selected row.
Sorry for my poor english. Thanks in advance.
What you need is possible and is not so complex. Look at the very old demo from the answer. If you have the column with name: 'myColName', and you want to insert any information in the edit or add form after the information about the column, you can just inset the row of data inside. The form contain <table>. So you should insert the <tr> having one or two child <td> elements (the cell for the label and the cell for the data). To be conform with other data in the form you should use class="FormData" for the <tr> element. The first <td> element (in the column for the labels) should has class="CaptionTD ui-widget-content" and the second <td> element (in the column for the data for the input of modification) should has class="DataTD ui-widget-content":
{ // edit options
recreateForm: true,
beforeShowForm: function ($form) {
var $formRow = $form.find('#tr_Name'); // 'Name' in the column name
// after which you want insert the information
$('<tr class="FormData"><td class="CaptionTD ui-widget-content">' +
'<b>Label:</b>' + // in the line can be any custom HTML code
'</td><td class="DataTD ui-widget-content">' +
'<span></span>' + // in the line can be any custom HTML code
'</td></tr>').insertAfter($formRow);
}
}
UPDATED: OK, now I understand what you want. The problem is that addRowData will be called for adding of new row with the option addedrow of editGridRow. So if you use reloadAfterSubmit: false option you can add the new row either as 'first' or as the 'last' in the grid. To be able to use 'after' or 'before' parameter of addRowData the method addRowData must be called with one more parameter which specify the id of the row before which (or after which) the new row will be inserted.
At the first look it seems that only with respect of modification of the source code of jqGrid your requirement can be implemented. In reality you can do implement your requirements with very small code and without modification of the source code of jqGrid. I suggest the following:
You can save the pointer to the original implementation of addRowData in a variable and overwrite it
with your implementation:
var oldAddRowData = $.fn.jqGrid.addRowData;
$.jgrid.extend({
addRowData: function (rowid, rdata, pos, src) {
if (pos === 'afterSelected' || pos === 'beforeSelected') {
if (typeof src === 'undefined' && this[0].p.selrow !== null) {
src = this[0].p.selrow;
pos = (pos === 'afterSelected') ? 'after' : 'before';
} else {
pos = (pos === 'afterSelected') ? 'last' : 'first';
}
}
return oldAddRowData.call(this, rowid, rdata, pos, src);
}
});
The code above introduce two new options of addRowData: 'afterSelected' and 'beforeSelected'. If you include the code before creating of jqGrid the grid will be created using your custom addRowData, so you can use new addedrow: 'afterSelected' or addedrow: 'beforeSelected' as the options of Add form.
The demo shows live that the suggestion work. You should don't look at many other code of the demo. The current implementation of form editing don't support local editing, but in I used in the demo just old code which do this. So the total code of the demo is relatively long, but the part which I want to demonstrate you can easy find inside.