I have a problem, I like to show a select text values of a MultiSelect control on a tooltip.
I only can show the value(numeric) from MultiSelect, this is my code:
var multiselect = $("#combo_multi").data("kendoMultiSelect");
value2 = multiselect.value(); //show only numeric values ->14376, etc.
Show the numeric values together without spaces. ->14376
I like to show the text value, not the numeric value.
I think I have to use an array for show the text value, but I don´t know how do it.
If somebody have the response of this problem, I appreciate the solution. Thanks.
Maybe this could help you a bit
var multiselect = $("#combo_multi").data("kendoMultiSelect");
var value2 = multiselect.value();
var selectedValues = value2.split(",");
var multiSelectData = multiselect.dataSource.data();
for (var i = 0; i < multiSelectData.length; i++) {
var numberValue = multiSelectData[i].number;
for (var j = 0; j < selectedValues.length; j++) {
if (selectedValues[j] == numberValue) {
// here we get description for value
var desc = multiSelectData[i].description;
break;
}
}
}
Example other
$("#multiselect").kendoMultiSelect();
var multiselect = $("#CityTo").data("kendoMultiSelect");
var dataItem = multiselect.dataItems();
//***Debug
var CityArray = new Array();
CityArray = dataItem;
alert(JSON.stringify(CityArray));
//***End Debug
//**************** Applied example
var newHtml = "";
var item = dataItem;
$.each(item, function (index, item) {
newHtml += '<div class="panel panel-default" ><div class="panel-heading">' + item.City_Name + '</div><div class="panel-body">Panel Content</div></div>';
});
$("#CityCount").html(newHtml);
You can see the details "dataItem" using "item."
item.City_Name
I'm on a newer version of Kendo UI so possibly things have changed since you asked this. I'll give you an updated answer..
var multiselect = $("#combo_multi").data("kendoMultiSelect");
var selectedValues = multiselect.value();
var multiSelectData = multiselect.dataSource.data();
var count = selectedValues.length;
for (var i = 0; i < multiSelectData.length; i++) {
if (selectedValues.indexOf(multiSelectData[i].Value) >= 0 ) {
//found, do something
var selectedText = multiSelectData[i].Text;
count--;
}
if (count == 0) {
break;
}
}
Related
Basically I want to use an auto-sorting script through the script editor in Google sheets, but I want it to smartly pick a range of rows, by only selecting those rows where a specific column has an empty cell.
All other rows that have that column's cell populated would stay put. Here is the sort code I've found.
/**
* Automatically sorts the 1st column (not the header row) Ascending.
*/
function onEdit(event){
var sheet = event.source.getActiveSheet();
var editedCell = sheet.getActiveCell();
var columnToSortBy = 1;
var tableRange = "A2:T99"; // What to sort.
if(editedCell.getColumn() == columnToSortBy){
var range = sheet.getRange(tableRange);
range.sort( { column : columnToSortBy, ascending: true } );
}
}
Thanks.
Note: this will only sort the values in the cells (metadata such as formats, notes etc will not be sorted, as they would with the GAS range.sort() method).
function onEdit(event)
{
var sheet = event.source.getActiveSheet();
var editedCell = sheet.getActiveCell();
var columnToSortBy = 0; // zero-based index
if (editedCell.getColumn() == columnToSortBy)
{
var columnToWatch = 5; // checking this column for blank cells (zero-based index)
var tableRange = "A2:T99"; // what to sort
var range = sheet.getRange(tableRange);
var data = range.getValues();
var dataCopy = data.slice();
dataCopy.sort(function(a, b) {return a[columnToSortBy] > b[columnToSortBy] ? 1 : (a[columnToSortBy] < b[columnToSortBy] ? -1 : 0);});
var j = -1;
for (var i = 0, length = data.length; i < length; i++)
{
if (data[i][columnToWatch].toString().length)
{
do j++; while (!dataCopy[j][columnToWatch].toString().length);
data[i] = dataCopy[j];
}
}
range.setValues(data);
}
}
I have a huge spreadsheet matrix, from which I create a long list of check boxes. The users then select different abilities, press search. The code the cross-checks with the database spreadsheet, returning names of the persons who has those abilities.
I need to update the "rightPanel" with the results of my search. But i simple can't figure out how to - if at all posible - update a panel in my UI..
var dataSSkey = 'sheetID'; //datasheet ID
var dataSheet = SpreadsheetApp.openById(dataSSkey).getSheetByName('Ansatte');
var groupsArray = [[],[],[],[]];
var lastRow = dataSheet.getLastRow();
var lastColumn = dataSheet.getLastColumn();
var dataArray = dataSheet.getRange(1,1,lastRow,lastColumn).getValues();
var numberGroups
var app = UiApp.createApplication().setTitle('Find Consultant');
var panel = app.createVerticalPanel();
var leftPanel = app.createVerticalPanel().setWidth(450);
var rightPanel = app.createVerticalPanel().setWidth(450);
var grid = app.createGrid(1, 2).setId('myGrid')
var outputArray = []; //to store output from search
var positiveList = [[],[]]; //array to store name and folder-ID of consultants matching
var numberPositive = 0; //number of consultants matching
function doGet() {
buildGroupsArray()
addCheckBoxesToUI()
var scrollPanel = app.createScrollPanel().setHeight(460);
//Search button
var searchButton = app.createButton('Search');
var clickHandler = app.createServerClickHandler("respondToSearch");
searchButton.addClickHandler(clickHandler);
clickHandler.addCallbackElement(panel);
var spacerImage = app.createImage("http://www.bi..ge.jpg").setHeight(3);
scrollPanel.add(panel);
rightPanel.add(app.createLabel('resultat her'));
leftPanel.add(scrollPanel);
leftPanel.add(spacerImage);
leftPanel.add(searchButton);
grid.setWidget(0, 0, leftPanel)
grid.setWidget(0, 1, rightPanel);
app.add(grid);
return app;
}
function respondToSearch(e){
var numberLogged = 0;
//define firstEmpty
var firstEmpty = "A"+lastRow;
if(lastRow !== 1){
firstEmpty = "A"+(lastRow+1);
};
//find selected competencies --> store in array + count competencies
for(i = 1; i <= lastRow; i++){
if (e.parameter["Checkbox"+i] == "true") {
var value = e.parameter["CheckboxValue"+i];
outputArray[numberLogged] = value;
numberLogged++;
}
}
for(i = 2; i <= lastColumn; i++){
var numberCorrect = 0;
//Run through rows according to content of output from selection
for(j in outputArray){
//Check if consultant own selected competency
if(dataArray[outputArray[j]][i] == "x"){
numberCorrect++; //if consultant owns selected competency then count
}
}
//if consultant owns all competencies, then add name and folder-id to array
if(numberCorrect == numberLogged){
positiveList[0][numberPositive] = dataArray[1][i]; //Add consultant name
positiveList[1][numberPositive] = dataArray[2][i]; //Add consultant-folder ID
numberPositive++ //count the number of consultants that own all competencies
}
}
for(j in positiveList[0]){
var name = positiveList[0][j];
var id = positiveList[1][j];
Logger.log(name);
Logger.log(id)
var anchor = app.createAnchor(name,'https://ww......folderviewid='+id);
rightPanel.add(anchor)
}
return app;
}
I don't really understand the problem you have...
In your handler function you only have to use app=UiApp.getActiveApplication() and from there populate the panel exactly the same way you did it in the doGet() function, ending with a return app; that will actually update the current Ui.
There are dozens of examples all around... did I misunderstand something in your question ?
Edit : following your comment.
I suppose you defined your variables outside of the doGet function hoping they will become global and so available to all the functions in your script but this is not going to work. Global variables in Google Apps script can't be updated by functions.
I would strongly recommend that you create app and panels in the doGet function and give them an ID so that you can get them back and update their values (or content) from the handler functions.
Here is a re-written version of your code (didn't test)
: (some parts are not reproduced (see //...)
var dataSSkey = 'sheetID'; //datasheet ID
var dataSheet = SpreadsheetApp.openById(dataSSkey).getSheetByName('Ansatte');
var groupsArray = [[],[],[],[]];
var lastRow = dataSheet.getLastRow();
var lastColumn = dataSheet.getLastColumn();
var dataArray = dataSheet.getRange(1,1,lastRow,lastColumn).getValues();
var numberGroups
var outputArray = []; //to store output from search
var positiveList = [[],[]]; //array to store name and folder-ID of consultants matching
var numberPositive = 0; //number of consultants matching
function doGet() {
var app = UiApp.createApplication().setTitle('Find Consultant');
var panel = app.createVerticalPanel();
var leftPanel = app.createVerticalPanel().setWidth(450).setId('leftPanel');
var rightPanel = app.createVerticalPanel().setWidth(450).setId('rightPanel');;
var grid = app.createGrid(1, 2).setId('myGrid')
buildGroupsArray(app); // in this function get app as parameter or use UiApp.getActiveApplication();
addCheckBoxesToUI(app);// in this function get app as parameter or use UiApp.getActiveApplication();
var scrollPanel = app.createScrollPanel().setHeight(460);
//...
//...
return app;
}
function respondToSearch(e){
//...
//...
var app = UiApp.getActiveApplication();
var rightPanel = app.getElementById('rightPanel');
for(j in positiveList[0]){
var name = positiveList[0][j];
var id = positiveList[1][j];
Logger.log(name);
Logger.log(id)
var anchor = app.createAnchor(name,'https://ww......folderviewid='+id);
rightPanel.add(anchor)
}
return app;
}
I'm having trouble to select text in CKEditor(3.6). As we use plain text i dont know how to use correctly the range selectors.
HTML code of the CKEditor:
<body spellcheck="false" class="rf-ed-b" contenteditable="true">
<br>
Cross those that apply:<br>
<br>
<br>
[«dummy»] If he/she is tall<br>
<br>
[«dummy»] If he/she is a male<br>
<br>
[«dummy»] If he/shi is a minor<br>
<br>
Specialties:<br>
<br>
[«dummy»] «Write here the specialties if known»<br>
<br>
<br>
«You are now done with filling in this form»<br>
</body>
With the keys 'CRTL+N' I want to go to the next filleble spot:
«[label]»
I tried stuff like:
var editor = CKEDITOR.instances['MyEditor'];
var findString = '«';
var element = editor.document.getBody();
var ranges = editor.getSelection().getRanges();
var startIndex = element.getHtml().indexOf(findString);
if (startIndex != -1) {
ranges[0].setStart(element.getFirst(), startIndex);
ranges[0].setEnd(element.getFirst(), startIndex + 5);
editor.getSelection().selectRanges([ranges[0]]);
}
Error:
Exception: Index or size is negative or greater than the allowed amount
While totally stripepd down it kinda works a bit:
var editor = CKEDITOR.instances['MyEditor'];
var ranges = editor.getSelection().getRanges();
var startIndex = 10;
if (startIndex != -1) {
ranges[0].setStart(element.getFirst(), startIndex);
ranges[0].setEnd(element.getFirst(), startIndex + 5);
editor.getSelection().selectRanges([ranges[0]]);
}
here it selects 5th till 10th char on first row.
I used the following sources:
example on Stackoverflow
Another stackoverflow example
CKEditor dom selection API
All solutions i can find work with html nodes.
How can set selection range on the '«' till next '»'
I've managed to solve this solution. Meanwhile i also upgraded CKeditor to 4.0.
This shouldnt have an impact on the solution.
It is a lot of code in JS.
On my keybinding i call the following JS function: getNextElement()
In this solution it also searches behind the cursor, this makes it possible to step through multiple find results.
Also the view gets scrolled to the next search result
var textNodes = [], scrollTo=0,ranges = [];
function getNextElement(){
var editor =null;
ranges = [];
// I dont know the ID of the editor, but i know there is only one the page
for(var i in CKEDITOR.instances){
editor = CKEDITOR.instances[i];
}
if(editor ==null){
return;
}
editor.focus();
var startRange = editor.getSelection().getRanges()[0];
var cursorData ="",cursorOffset=0,hasCursor = false;
if(startRange != null && startRange.endContainer.$.nodeType == CKEDITOR.NODE_TEXT){
cursorOffset = startRange.startOffset;
cursorData = startRange.endContainer.$.data;
hasCursor = true;
}
var element;
element = editor.document.getBody().getLast().getParent();
var selection = editor.getSelection();
// Recursively search for text nodes starting from root.
textNodes = [];
getTextNodes( element );
var foundElement = false;
foundElement = iterateEditor(editor,hasCursor,cursorData,cursorOffset);
if(!foundElement){
foundElement =iterateEditor(editor,false,"",0);
}
if(foundElement){
// Select the range with the first << >>.
selection.selectRanges( ranges );
jQuery(".cke_wysiwyg_frame").contents().scrollTop(scrollTo);
}
}
function iterateEditor(editor,hasCursor,cursorData,cursorOffset){
var foundElement = false;
var rowNr = 0;
var text, range;
var foundNode = false;
if(!hasCursor){
foundNode = true;
}
// Iterate over and inside the found text nodes. If some contains
// phrase "<< >>", create a range that selects this word.
for (var i = textNodes.length; i--; ) {
text = textNodes[ i ];
if ( text.type == CKEDITOR.NODE_ELEMENT && text.getName() == "br" ){
rowNr++;
} else if ( text.type == CKEDITOR.NODE_TEXT ) {
var sameNode = false;
if(text.$.data == cursorData){
foundNode = true;
sameNode = true;
}
if(foundNode){
var startIndex = -1;
var endIndex = 1;
if(sameNode){
// Check inside the already selected node if the text has multiple hits on the searchphrase
var indicesStart = getIndicesOf('\u00AB', text.getText());
var indicesEnd = getIndicesOf('\u00BB', text.getText());
for (var j = indicesStart.length; j--; ) {
if(indicesStart[j] > cursorOffset){
startIndex = indicesStart[j];
endIndex = indicesEnd[j];
}
}
} else{
startIndex = text.getText().indexOf( '\u00AB' );
endIndex = text.getText().indexOf( '\u00BB' );
}
if ( startIndex > -1 && (!sameNode || startIndex > cursorOffset)) {
range = editor.createRange();
range.setStart( text, startIndex );
foundElement = true;
// calculate the height the window should scroll to focus the selected element
scrollTo = (rowNr)*20;
}
if ( endIndex > -1 && foundElement ) {
range.setEnd( text, endIndex+1 );
ranges.push( range );
return true;
}
}
}
}
}
function getIndicesOf(searchStr, str) {
var startIndex = 0, searchStrLen = searchStr.length;
var index, indices = [];
while ((index = str.indexOf(searchStr, startIndex)) > -1) {
indices.push(index);
startIndex = index + searchStrLen;
}
return indices;
}
function getTextNodes( element ) {
var children = element.getChildren(), child;
for ( var i = children.count(); i--; ) {
child = children.getItem( i );
textNodes.push( child );
}
}
I'm having a similar issue to this question - however I am requiring to get 2 e.parameters of both 1st and 2nd list boxes in order to populate the spreadsheet for the 3rd list box.
The vert is being read by the e.parameter, but the chan is undefined, which I do not understand as it is fully functional in the second list box but not the third.
Is there something that I have overseen in this code?
var channelBox = app.createListBox().setId('channelBox').setName('channelBox').setWidth(152).setHeight(22);
var chanHandler = app.createServerChangeHandler('showChannelinfo');
chanHandler.addCallbackElement(channelBox);
channelBox.addChangeHandler(chanHandler);
var chaArray = ['Select channel','--','Email','Phone','Chat']; for (var i=0;i<chaArray.length;++i) {channelBox.addItem(chaArray[i]);};
var verticalBox = app.createListBox().setId('verticalBox').setName('verticalBox').setWidth(152).setHeight(22);
var vertHandler = app.createServerChangeHandler('showVerticalinfo');
vertHandler.addCallbackElement(verticalBox);
verticalBox.addChangeHandler(vertHandler);
function showChannelinfo(e){
var app = UiApp.getActiveApplication();
var itemSpreadsheetKey = 'ABC------------123';
var openedSS = SpreadsheetApp.openById(itemSpreadsheetKey);
var sheetList3 = openedSS.getSheetByName("boolean3");//Vertical Lookup Sheet
var channelBox = app.getElementById('channelBox');
var verticalBox = app.getElementById('verticalBox');
var chan = e.parameter.channelBox;
if (chan == 'Phone')
{ verticalBox.clear();
var marketFilter = sheetList3.getRange('A1').setFormula('=iferror(filter(boolean2!A:D,boolean2!B:B=TRUE))');}
if (chan == 'Email')
{ verticalBox.clear();
var marketFilter = sheetList3.getRange('A1').setFormula('=iferror(filter(boolean2!A:D,boolean2!D:D=TRUE))');}
if (chan == 'Chat')
{ verticalBox.clear();
var marketFilter = sheetList3.getRange('A1').setFormula('=iferror(filter(boolean2!A:D,boolean2!C:C=TRUE))');}
var numItemList1 = sheetList3.getLastRow();//get the item array
var list1ItemArray = sheetList3.getRange(1,1,numItemList1).getValues();//Add the items in ListBox
for(var i=0; i<list1ItemArray.length; i++)
{verticalBox.addItem(list1ItemArray[i][0]);}
if (chan == '--')
{verticalBox.clear();
var vertArray = ['Select vertical','Hardware','Apps','Ebooks','Movies','Music','Nik','Shopping','Places','Wallet','YouTube','BeatThatQuote'];
for (var i=0;i<vertArray.length;++i) {verticalBox.addItem(vertArray[i]);};}
return app
};
function showVerticalinfo(e){
var app = UiApp.getActiveApplication();
var itemSpreadsheetKey = 'ABC------------123';
var openedSS = SpreadsheetApp.openById(itemSpreadsheetKey);
var sheetList4 = openedSS.getSheetByName("boolean4");//Language Lookup Sheet
var channelBox = app.getElementById('channelBox');
var verticalBox = app.getElementById('verticalBox');
var langBox = app.getElementById('langBox');
var chan = e.parameter.channelBox;
var vert = e.parameter.verticalBox;
langBox.clear();
var langFilter = sheetList4.getRange('A1').setFormula('=iferror(filter(boolean!A:D,boolean!A:A="' + chan + '",boolean!B:B="' + vert + '",boolean!D:D=TRUE))');
//**this returns as chan = undefined**
var numItemList2 = sheetList4.getLastRow();//get the item array
var list1ItemArray2 = sheetList4.getRange(1,3,numItemList2).getValues();//Add the items in ListBox
for(var i=0; i<list1ItemArray2.length; i++){langBox.addItem(list1ItemArray2[i][0]);}
if (chan == '--')
{langBox.clear();
var langArray = ['Select language','Dutch','French','German','Italian','Portuguese', 'Russian','Spanish'];
for (var i=0;i<langArray.length;++i) {langBox.addItem(langArray[i]);};}
return app
};
If anyone can use their magic eyes to give me any advice, it would be greatly appreciated!
The problem is with your callbackElement.
What I suggest is that you put both these list boxes into a single panel and add this panel as the callback element to both the handlers. Something like
function doGet(){
/* Your other code here */
var panel = app.createVerticalPanel().setId('panel');
var channelBox = app.createListBox().setId('channelBox').setName('channelBox').setWidth(152).setHeight(22);
var chanHandler = app.createServerChangeHandler('showChannelinfo');
chanHandler.addCallbackElement(panel); /* Add panel as the callback element */
channelBox.addChangeHandler(chanHandler);
var chaArray = ['Select channel','--','Email','Phone','Chat']; for (var i=0;i<chaArray.length;++i) {channelBox.addItem(chaArray[i]);};
var verticalBox = app.createListBox().setId('verticalBox').setName('verticalBox').setWidth(152).setHeight(22);
var vertHandler = app.createServerChangeHandler('showVerticalinfo');
vertHandler.addCallbackElement(panel); /* Add panel as the callback element */
verticalBox.addChangeHandler(vertHandler);
panel.add(channelBox);
panel.add(verticalBox);
/* Your other UI Code here */
}
I have an editable <iframe> with the some HTML code in it. I need get all <a> tags in my range. I tried this code but it doesn't work:
var select = document.getElementById(iframe_id).contentWindow.getSelection();
var range = select.getRangeAt(0);
//HERE I WANT TO FIND ALL TAGS IN THIS RANGE AND IF IT "A" - ADD NEW ATTRIBUTE "CLASS". SOMETHING LIKE THIS
var parent = rng.commonAncestorContainer;
for(var i=0; i<parent.childNodes.length; i++)
{
if(parent.childNodes[i].tagName.toLowerCase() == "a")
parent.childNodes[i].setAttribute("class", "href_class");
}
You can use getElementsByTagName() to get all <a> tags of the range container and then check for each of them whether it actually belongs to the range using range.compareBoundaryPoints() (only parts of the container might be selected). Something like this:
var links = rng.commonAncestorContainer.getElementsByTagName("a");
for (var i = 0; i < links.length; i++)
{
var linkRange = document.createRange();
linkRange.selectNode(links[i]);
if (rng.compareBoundaryPoints(Range.START_TO_START, linkRange) <= 0 && rng.compareBoundaryPoints(Range.END_TO_END, linkRange) >= 0)
{
links[i].className = "href_class";
}
}
This should get you started in the right direction. This code does not do any null reference checks on the iframe, selection, range or list.
function addAnchorClass(targetFrameId) {
var targetIframe = document.getElementById(targetFrameId).contentWindow;
var selection = targetIframe.getSelection();
var range = selection.getRangeAt(0);
var alist = range.commonAncestorContainer.getElementsByTagName("a");
for (var i=0, item; item = alist[i]; i++) {
if (selection.containsNode(item, true) ) {
item.className += "PUT YOUR CSS CLASS NAME HERE";
}
}
}