Excel add-in JavaScript - Get last selected cell - javascript

I'm trying to be able to get the details of the last selected cell - value, address, etc.
So far, I couldn't achieve this - the closest I got to is getting the currently selected cell, which apparently doesn't serve my needs.
Thanks!

If you are trying to get a reference to the previously selected cell, the following works. Create a global variable called lastRangeAddress. Then assign a handler to the Workbook.onSelectionChanged event. The following is a handler that turns the current cell yellow and last (that is, previously selected) cell selected blue. The easiest way to see this work is to install Script Lab in Excel. Open it in Excel and open the Selection Changed snippet. Add the global variable just below the button handler assignment statements near the top: let lastRangeAddress: string;. Then replace the onSelectionChange method with the one below. Open the Run pane in Script Lab, press the Add event handler button, and then start clicking cells.
To read properties of the lastRange, you would need to load them and sync.
async function onSelectionChanged() {
tryCatch(() => Excel.run(async (context) => {
if (lastRangeAddress) {
const lastRange = context.workbook.worksheets.getActiveWorksheet().getRange(lastRangeAddress);
lastRange.format.fill.color = "blue";
}
const range = context.workbook.getSelectedRange();
range.format.fill.color = "yellow";
range.load("address");
await context.sync();
lastRangeAddress = range.address;
}));
}

Related

Office Add-ins Javascript - How to simulate tab or enter key to choose cell inside a range

I am developing an Excel Office Add-ins, I need to select a range, and read the data from each cell of that range when I press Tab key or Enter key (to highlight cell from left to right, top to button). How do I read the highlight cells? The Excel.Range class https://learn.microsoft.com/en-us/javascript/api/excel/excel.range?view=excel-js-preview doesn't have anything like that. Thank you!
Unfortunately, Office JS does not provide a method to change an active cell in a range object, based on your description of the scenario, we have a workaround solution for your scenario.
You could get the range of the cell after the end-user clicks the button by range.getOffsetRange(rowOffset, columnOffset) and then you could use that range object of this cell to set it active, therefore it would be able to TTS
await Excel.run(async (context) => {
const range = context.workbook.getActiveCell();
var activeCell = range.getOffsetRange(0,1);
activeCell.select();
await context.sync();
});

<ng-select > after on changes formGroup control value still null,if searchTerm provided programmatically

I have requirement to set searchTerm value Programmatically(using Virtual keypad) and search the dropdown should show searchterm based options.
where form control is updateOn:'blur'.
But here i am facing issue like form control is not getting updated after selecting dropdown option based on searchTerm provided by virtual input key(in example stackblitz red color text control value is null).
Steps:
1.press virtual key pad button
2.select any option
3.now check red color text value:
Thanks.
It is getting updated, but you are using before it is updated. Even if you open the <ng-select> yourself, it will show different values in black and red.
If you can, I'd suggest for you to use change.id instead:
this.afterChangesFormControlValue = change.id;
But if you can't... if you wrap it inside a setTimeout(), even with a 0 delay, it will start working, since the setTimeout will be triggered only after the update is done:
setTimeout(() => {
console.log('on select option after given search term from virtual keyboar')
console.log("change:",change)
console.log("form control value:",this.form.controls.example.value)
this.afterChangesFormControlValue=this.form.controls.example.value;
}, 0);
Both should produce the same results - they did when I tested in your Stackblitz, but setTimeout is a bit unsightly.

TestCafe test script checkbox.checked always return false even when checked, how can I check the checkbox state in an if-condition?

Here is a summary of my problem:
We have a table with check boxes and file names in a file sharing application.
At the top of the table is a Set Preview button that lets the preview carousel to always display the default preview item.
Users can click a check box and click the set preview button and the preview item will change and the preview carousel will update.
I have a test automation script that tests this behavior written in JavaScript using TestCafe, NodeJS & ES6.
When we test the set Preview we click the checkbox for the item that we want to set the preview for.
Then we click the Set Preview button.
Confirm that the preview icon is set on that row where we just clicked the checkbox.
There are some things to note:
When the user clicks the checkbox, if the checkbox that is selected already has the preview set to that row, than the set preview button is disabled.
Also when the set preview is clicked, whatever row was checked is automatically unchecked.
So if a row that already has a preview set on it is checked then the user will not be able to click the set preview and hence the checkbox is never unchecked.
When the loop resets and the next item is checked, there are now two items that are checked and the set preview is disabled, because it's not possible to set two items with the set preview.
I've added code to check if the current row is checked and if it is; to uncheck it.
The trouble is that when I check the state of the checkbox to see if it is checked:
var checkbox = await projectDetails.tableRowCheckBox(fileName);
if (checkbox.checked === true) {
This returns false, even though the checkbox is checked. So it never gets unchecked and the script is failing.
The TestCafe website gives a similar example of how to do this here:
https://devexpress.github.io/testcafe/documentation/test-api/actions/click.html
So I figured it should work, and there are a few other forms out on the internet that show similar if-condition checks on check-boxes, so this seems like valid code, but yet it still isn't working.
One possible solution I haven't yet tried is to check if the preview row is already set to the current row, and if it is to skip that row completely. However, even if that solves my over-all problem, I'd still like to solve this problem. That is why I have posted it here.
EDIT: On another note, before I added the if-condition (that is failing), it seemed to me that I had the click in there, and I ran the script, and the cursor moved to the checkbox to unselect it, but it didn't actually uncheck the checkbox. Although I could have been mistaken and it was just re-selecting the checkbox after doing the set Preview, which itself automatically unselected the checkbox. (OK now my head is really going in circles)
More complete code:
for (var j = 0; j < dataElementCount; j++) {
// Act
await t.click(projectDetails.tableRowCheckBox(fileName).with({ selectorTimeout: 30000}));
await t.click(projectDetails.setPreviewButton, { selectorTimeout: 5000 });
// Assert
var previewRow = projectDetails.previewRow;
// NOTE: Do not feed in test data that doesn't support the preview, or setting the preview will fail for that item.
// tif and tiff files are not supported for the preview.
await t.expect(projectDetails.rowFileName(previewRow).textContent).eql(fileName);
// Cleanup
// We have to now unselect the item that was just selected, because if we don't then when we go to select the next one,
// the setPreview will fail, because two items would be selected at the same time.
// Yes multi-select is now a thing, and we have to deal with it.
// NOTE: Multi-select may be a thing, but it really only gets in our way with this workflow,
// if we click a checkbox above for an item that already has the preview set.
// After the SetPreview button is clicked the checkbox is unclicked,
// but if the preview is already set for an item, then the item never gets unclicked.
var checkbox = await projectDetails.tableRowCheckBox(fileName);
if (checkbox.checked === true) {
await t.click(projectDetails.tableRowCheckBox(fileName).with({ selectorTimeout: 30000}));
} else {
await t.wait(5000);
console.log('DENIED: The checkbox is NOT checked for the checkbox with the row filename: ' + fileName);
await t.wait(5000);
}
}
Selectors:
const rowFileName = row => row.find('td[data-label="Name"] span');
const setPreviewButton = Selector('div.table-actions')
.find('a.set-preview-button');
const tableRowCheckBox = filename => tableRowName(filename)
.sibling()
.find('td.checkbox-cell span.check');
const previewRow = Selector('td.table-preview-column span')
.filter(node => node.childElementCount === 1)
.parent('tr');
Sorry I cannot give access to the website itself, as that would be a breach of Intellectual Property.
I hope I've included all the information that I can to find a possible solution.
Thank you in advance for any help you can give!
The method:
const tableRowCheckBox = filename => tableRowName(filename)
.sibling()
.find('td.checkbox-cell span.check')
is targeting a <span class="check"> element.
So when you are calling this helper method:
var checkbox = await projectDetails.tableRowCheckBox(fileName);
you obtain a <span>. The problem is that the checked property only exists for <input type="checkbox"> element and does not exist on <span> element.
This means checkbox.checked is always undefined
Your code should be:
const tableRowCheckBox = filename => tableRowName(filename)
.sibling()
.find('td.checkbox-cell span')
.nth(0);
const checkbox = projectDetails.tableRowCheckBox(fileName);
const isChecked = await checkbox.hasClass('check');
if ( isChecked ) {
...
}

CKEDITOR 4.3.2 IE11 Permission Denied

So I am writing a plugin for ckeditor (#mentions).
When you type some characters (example "#John") a drop down will appear of a list of Johns that the user can select . When the users selects the drop down they want, it needs to remove the the "#John" text and insert an element that was retrieved from the dropdown. The problem occurs when trying to insert text, remove some text and setting the currsor position.
The Code
var html = '<span>InsertedElement</span> ';
// Create the Element to insert
var newElement = CKEDITOR.dom.element.createFromHtml(html, mentions.editor.document);
//Insert the element
mentions.editor.insertElement(newElement);
//Get a new bookmark
var tempBookMark = mentions.editor.getSelection().createBookmarks(true);
// get the data
var edata = mentions.editor.getData();
// set it with the exact same info so not changes (just for the test)
mentions.editor.setData(edata);
//set the bookmark
mentions.editor.getSelection().selectBookmarks(tempBookMark);
//focas on that position
mentions.editor.focus();
The issue
This works just fine on chrome however on IE11 after the text has been removed, when I try to access the mentions.editor.getSelection() I get "permission denied" error. I cannot set the bookmark and the focus is moved to the start of the ckeditor.
[Update]
A further test I performed narrowed down the issue. Commenting out the mentions.editor.setData(edata); line it stops erroring. If I use the setData function on the editor instance and then try to to run the GetSelection() on the Editor instance it errors (permission denied) in IE11 but works in Chrome. Its seems the setData function locks the editor in some way in IE11? I have simplified the code to allow it to be more easily replicated.
the Editor#setData is an asynchronous function. You cannot use selection right after setting data - you have to wait until everything is ready. Therefore setData accepts callback.
mentions.editor.setData( edata, function() {
//set the bookmark
mentions.editor.getSelection().selectBookmarks(tempBookMark);
//focas on that position
mentions.editor.focus();
} );

How to update ZK Grid values from jQuery

I have three Tabs and in each tab, I have a Grid.
The data for each Grid is coming from a database, so I am using rowRenderer to populate the Grids. The following code is common for all three Grids:
<grid id="myGrid1" width="950px" sizedByContent="true" rowRenderer="com.example.renderer.MyRowRenderer">
The rows are constructed from Doublebox objects. The data is populated successfully.
The Problem:
I need to handle multiple-cell editing on the client side. The editing is done via mouse-clicking on a particular cell and entering a value.
As example let's say that the user edits first cell on the first row and the value should be
propagated to all other cells on the same row and in all three Grids (so also the two Grids which the user currently does not see, because they are in tabpanes).
I am using jQuery to do this value propagation and it works OK.
I am passing the jQuery as follows:
doublebox.setWidgetListener(Events.ON_CHANGING, jQuerySelectors);
doublebox.setWidgetListener(Events.ON_CHANGE, jQuerySelectors);
This makes it possible to change the value in 1 cell and the change is instantly (visually) seen in all other cells filtered by jQuery selectors.
The problem is that the value is visually distributed to all the cells, but when I try to save the Grid data back to the database, the background values are the old ones.
I am assuming that ZK-Grid component is not aware that jQuery changed all the cell values. Nevertheless if I manually click on a cell that already has the NEW value (enter/leave/change focus) when I save the grid the NEW value is correct in that particular cell. Maybe that's a hint how can I resolve this.
Code of how I extract the Grid values:
Grid tGrid = (Grid) event.getTarget().getFellow("myGrid1");
ListModel model = tGrid.getModel();
MyCustomRow tRow = (MyCustomRow)model.getElementAt(i);
The model for my Grid is a List of MyCustomRow:
myGrid1.setModel(new ListModelList(List<MyCustomRow> populatedList));
I have a couple of assumptions, but whatever I have tried, hasn't worked. I have in mind that jQuery events and ZK-Events are different and probably isolated in different contexts. (Although I have tried to fire events from jQuery and so on..)
Do you have any suggestions? As a whole is my approach correct or there's another way to do this? Thanks for your time in advance!
Your problem is exactly what you are expecting.
Zk has it's own event system and do not care about your jq,
cos it's jq and zk don't observ the DOM.
The ways to solve your problem.
Use the "ZK-Way":
Simply listen at server-side and chage things there.
I am not sure if not selected Tabs
are updateable, but I am sure you could update the Grid
components on the select event of the Tab.
Fire an zk-event your self:
All you need to know, is written in the zk doc.
Basically, you collect your data at client side, send
an Event to the server via zAu.send() extract the
data from the json object at serverside and update your Grids
I would prefer the first one, cos it's less work and there should not be
a notable difference in traffic.
I post the solution we came up with:
This is the javascript attached to each Doublebox in the Z-Grid
//getting the value of the clicked cell
var currVal = jq(this).val();
//getting the next cell (on the right of the clicked cell)
objCells = jq(this).parents('td').next().find('.z-doublebox');
// if there's a next cell (returned array has length) - set the value and
// fire ZK onChange Event
if (objCells.length) {
zk.Widget.$(jq(objCells).attr('id')).setValue(currVal);
zk.Widget.$(jq(objCells).attr('id')).fireOnChange();
} else { //otherwise we assume this is the last cell of the current tab
//So we get the current row, because we want to edit the cells in the same row in the next tabs
var currRow = jq(this).parents('tr').prevAll().length;
//finding the next cell, on the same row in the hidden tab and applying the same logic
objCellsHiddenTabs = jq(this).parents('.z-tabpanel').next().find('.z-row:eq(' + currRow + ')').find('.z-doublebox');
if (objCellsHiddenTabs.length) {
zk.Widget.$(jq(objCellsHiddenTabs).attr('id')).setValue(currVal);
zk.Widget.$(jq(objCellsHiddenTabs).attr('id')).fireOnChange();
}
}
The java code in the RowRenderer class looks something like this:
...
if (someBean != null) {
binder.bindBean("tBean", someBean);
Doublebox box = new Doublebox();
setDefaultStyle(box);
row.appendChild(box);
binder.addBinding(box, "value", "tBean.someSetter");
...
private void setDefaultStyle(Doublebox box) {
box.setFormat("#.00");
box.setConstraint("no negative,no empty");
box.setWidth("50px");
String customJS = ""; //the JS above
//this is used to visually see that you're editing multiple cells at once
String customJSNoFireOnChange = "jq(this).parents('td').nextAll().find('.z-doublebox').val(jq(this).val());";
box.setWidgetListener(Events.ON_CHANGING, customJSNoFireOnChange);
box.setWidgetListener(Events.ON_CHANGE, customJS);
}
What is interesting to notice is that ZK optimizes this fireOnChange Events and send only 1 ajax request to the server containing the updates to the necessary cells.

Categories

Resources