Is it possible to set column name dynamically on a dojo grid? - grid

Is there any way to set a dynamic name for column header, for example in a formatter function!?
I'll have a popup menu on the grid and depending on the chosen option it should change the name displayed in the column header.

Its quite easy if you use dojo.query
var grid = dijit.byId('myGridId'), NewHeader = "Foo Bar Text Content";
var columnHeaderNodes = dojo.query(
'.dojoxGridHeader table th',
grid.viewsHeaderNode)
var nthColumn = 12;
// if has child and its not a textnode - this may happen
// when there is a listener (dnd, click) attached for sorting etc.
if(columnHeaderNodes[nthColumn].firstChild && columnHeaderNodes[nthColumn].firstChild.nodeType != 3)
tgt = columnHeaderNodes[nthColumn].firstChild;
else tgt = columnHeaderNodes[nthColumn];
tgt.innerHTML = NewHeader;

Related

Google script to automatically detect the cell containing a button, and change the background of that cell?

I'm a teacher working on creating a Jeopardy-style game to use in my classroom. I'm very new to Google scripts and coding in general. I'm creating "buttons" for the point values in each category using transparent images and attaching script to change the background color of the cell to grey on click to indicate which point values have already been used, as in this example.
What I would like to do is be able to assign the same exact script to each "button," so that it will automatically detect which cell to change to grey based on which button is pushed. I haven't been able to figure this out, and instead have created a separate script for each button (Category 1, 100 pts; Category 2, 100 pts; Category 3, 100 pts, etc etc). It's complicated and time-consuming, and it just seems like there has to be a better way!
function colorCat1100(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var colors = [
["#e0e0e0"]
];
var cell = sheet.getRange("A3:A3");
cell.setBackgrounds(colors);
}
function colorCat2100(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var colors = [
["#e0e0e0"]
];
var cell = sheet.getRange("B3:B3");
cell.setBackgrounds(colors);
}
function colorCat3100(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var colors = [
["#e0e0e0"]
];
var cell = sheet.getRange("C3:C3");
cell.setBackgrounds(colors);
}
function colorCat4100(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var colors = [
["#e0e0e0"]
];
var cell = sheet.getRange("D3:D3");
cell.setBackgrounds(colors);
}
function colorCat5100(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var colors = [
["#e0e0e0"]
];
var cell = sheet.getRange("E3:E3");
cell.setBackgrounds(colors);
}
...and this is just the first row of points values. I would greatly appreciate any help you wonderful people might have to offer! Thanks in advance!
Issue:
Images can be inserted to a sheet either (1) belonging to a cell (Insert > Image > Image in cell, or using IMAGE), and to which scripts cannot be attached, or (2) not belonging to a specific cell (Insert > Image > Image over cells), to which scripts can be attached.
Assuming you are using Image over cells, you cannot pass parameters to a function that is attached to the image. And considering that images inserted via Image over cells don’t belong to a specific cell, there is no way for the called function to get information on which image has been clicked via getCurrentCell() or getActiveRange().
Workaround: onSelectionChange trigger:
Thanks to the recently added onSelectionChange(e) trigger, you could use the cells themselves as “buttons”: you can run the script when a cell is clicked, instead of attaching the script to over-cell images.
The idea is that, when there is a change on which cell is selected, the script will run and check whether the currently selected cell is one of the ones with "buttons" (this condition is needed to avoid all cells to change background when they're clicked, but only the "button" ones). And if it is, the cell background will be changed.
Just copy and paste the following code:
function onSelectionChange(e) {
var buttonRanges = ["A3", "B3", "C3"]; // Cells with "buttons" (please change)
var range = e.range;
if (buttonRanges.includes(range.getA1Notation())) {
range.setBackground("#e0e0e0");
}
}
Of course, you could add the images themselves to the cells, but instead of using Image over cells, you should add inline cells, either via Image in cell or with =IMAGE.
Note:
In the beginning of this function, the A1 notations of the cells with buttons are defined. In the provided sample, these cells are A3, B3 and C3. Please change according to your preferences.
This will not work if the clicked cell is not the previously selected cell one (only cell selection changes are tracked by this trigger).
Reference:
onSelectionChange(e)

Different renderers for datagrid in flex 4.0

I'm working in flex 4.0 and I have a data grid with three columns. The second column should display the selection(s) the user has made according to the these rules: if they selected only one name display a label with the name in that grid cell, if they chose more than one name then a drop down list should be displayed with a title "Multiple Selected" and the drop down when clicked will show all the names associated for that entry. Therefore the second column can have a mixture of labels and drop down lists. As an example the first entry they chose only one person, so for the first row the second column it shows a label with the person's name. Then in the second entry say they chose 2 names, the second row second column shows a drop down list with the two names in the drop down list. As you can see the second column has a label and a drop down list mixture. Note the selection process is not taking place in the datagrid, the information is simply being supplied by means of setting the dataprovider for the datagrid.
I figure it out you make a itemrenderer with both the label and the dropdown list but you disable one while enabling the other when the conditions are met. The only problem with this approach is I modify the width as well because the label comes first and pushes the drop down list to the right (even when it isn't visible and sometimes beyond the width of the column). So I adjust the widths of each component (setting one to 100% while the other is 0% depending on which is to be visible) but for some reason when I update the data it does not immediately change the cell, only if I click on the header does it change the width and the visibility. I think this is because the UI does not commit the width adjusts immediately? I know it's the width because if I comment out the width adjustments once my data gets updated you see the change right away in the datagrid. For instance if I have not chosen yet the names of my selection, the cell is blank. Then I make a selection of just one person then it shows right away the name in the cell using the label component. Then if I select another name the data gets updated again and you see in the data cell some space (this is the label thats invisible but has some text which causes some empty space) and the drop down list with the names of the ones selected and again it's an immediately effect I don't have to click on the grid to update it. Here's the code with the width adjustments uncommented:
protected function mxdatagriditemrenderer1_dataChangeHandler(event:FlexEvent):void
{
if(data.judgmentpart.JudgmentDebtors.length ==1)
{//display label and disable the dropdown list
lblData.visible = true;
lblData.enabled = true;
lblData.percentWidth = 100;
DDLdatagrid.visible = false;
DDLdatagrid.enabled = false;
DDLdatagrid.percentWidth = 0;
}
else if (data.judgmentpart.JudgmentDebtors.length >1)
{
lblData.visible = false;
lblData.enabled = false;
lblData.percentWidth = 0;
DDLdatagrid.visible = true;
DDLdatagrid.enabled = true;
DDLdatagrid.percentWidth = 100;
}
else
{
lblData.visible = false;
lblData.enabled = false;
lblData.percentWidth = 0;
DDLdatagrid.visible = false;
DDLdatagrid.enabled = false;
DDLdatagrid.percentWidth = 0;
}
}
protected function mxdatagriditemrenderer1_creationCompleteHandler(event:FlexEvent):void
{
lblData.visible = false;
lblData.enabled = false;
lblData.percentWidth = 0;
DDLdatagrid.visible = false;
DDLdatagrid.enabled = false;
DDLdatagrid.percentWidth = 0;
}
]]>
</fx:Script>
<s:HGroup width="100%" verticalAlign="middle">
<s:Label id="lblData" text="{data.judgmentpart.JudgmentDebtors}"
/>
<s:DropDownList id="DDLdatagrid" dataProvider="{data.judgmentpart.JudgmentDebtors}"/>
</s:HGroup>
</s:MXDataGridItemRenderer>

Add css style into textnode dynamically

I'm having a problem of adding a css style into the auto generated textnode. I know that the textnode does not has any parent node. So I cannot just append the css style in it.
Basically, what I need to do is when user clicks on the "+" button which I create it in the page and it will add a new textnode into one of the . When the user clicks one more time, and it will add another new textnode continually. However, I would like to add a css style after the textnode is created.
Here is my code:
function addRowToTable() {
//find the last row in the table and add the new textnode when user clicks on the button
var tbl = document.getElementById('audioTable2');
var lastRow = tbl.rows.length;
var iteration = lastRow;
var row = tbl.insertRow(lastRow);
//after find the last row in the table, and it will add the new cell with the new textnode
var cellLeft = row.insertCell(0);
var el_span = document.createElement('span');
var el_spanClass = el_span.setAttribute('class', 'test');
var textNode = document.createTextNode(iteration);
cellLeft.appendChild(textNode);
}
//this is the css style I would like to apply into the new gerenated textnode
function appendStyle(styles){
var css = document.createElement('style');
css.type='text/css';
if (css.styleSheet) css.styleSheet.cssText = styles;
else css.appendChild(document.createTextNode(styles));
document.getElementsByTagName("head")[0].appendChild(css);
}
Could someone help me on this? Thanks a lot.
You say: "I'm having a problem of adding a css style into the auto generated textnode," but the code you provide shows that you are trying to add a style element to the head for every new textnode. I think what you want is to either 1) apply a style already defined in your style sheet to the textnode, or 2) directly style the textnode inline. Therefore, I think your code should be either:
1) Apply a style in your css stylesheet to the textnode via the span:
//after find the last row in the table, and it will add the new cell with the new textnode
var cellLeft = row.insertCell(0);
var el_span = document.createElement('span');
var el_spanClass = el_span.setAttribute('class', 'test');
var textNode = document.createTextNode(iteration);
cellLeft.appendChild(el_span);
el_span.appendChild(textNode);
}
This puts the span into the cell (which you don't do in your code) which would then wrap the textnode with the span giving it a class of test.
2) Apply a style directly (inline) to the textnode via the span:
//after find the last row in the table, and it will add the new cell with the new textnode
var cellLeft = row.insertCell(0);
var el_span = document.createElement('span');
el_span.setAttribute('style', 'color: red'); /*just an example, your styles set here*/
var textNode = document.createTextNode(iteration);
cellLeft.appendChild(el_span);
el_span.appendChild(textNode);
}
In either case, your appendStyle function could be deleted.

cObject in Typolink assigned with border-content

Basically, I (think I ) need to know how to assign borderContent to a cObject, when it is a typolink parameter.
To tell the whole story: I'm using perfect lightbox, and I want it to open the lightbox when a text is clicked, and display the images that are in a single content element in the border section.
Looking through the manual, i found this code:
page.20 = TEXT
page.20.value = Open an image in a lightbox
page.20.typolink {
title = This is my caption
parameter.cObject = IMG_RESOURCE
parameter.cObject = fileadmin/image2.jpg
parameter.cObject.file.maxW = 600
parameter.cObject.file.maxH = 600
ATagParams = rel="lightbox[mySet]"
}
which is working fine. But I don't want the path to be hard set, but the content to be loaded from the border section, as I said. But if I try the following:
page.20 = TEXT
page.20.value = Open an image in a lightbox
page.20.typolink {
title = This is my caption
parameter.cObject = IMG_RESOURCE
parameter.cObject < styles.content.getBorder
parameter.cObject.file.maxW = 600
parameter.cObject.file.maxH = 600
ATagParams = rel="lightbox[mySet]"
}
the link is gone.
So I GUESS I'm assigning the content wrong. Somebody knows the answer?
Thanks!
(If of any help, I use automaketemplate..)
Assigning styles.content.getBorder will just assign the full content elements from the border column. This will not get you anywhere.
You will need to manually load the content elements from the border column, of course this can be done with TypoScript. It should be something like this:
page.20 = TEXT
page.20 {
value = Open an image in a lightbox
typolink {
ATagParams = rel="lightbox[mySet]"
title = This will be the title attribute
parameter.cObject = CONTENT
parameter.cObject {
table = tt_content
select {
pidInList = this
where = colPos = 3
}
renderObj = IMG_RESOURCE
renderObj.file {
import = uploads/pics
import.field = image
import.listNum = 0
width = 600
height = 600
}
}
}
}
Basically this will load all content elements on the border position from the current page. Render the first image in the list of images and return you the resource.

Styling UITextField

I've been playing around with different methods of determining at runtime the width of a "label" so that I can resize the "label" because I don't want it to truncate. I've finally found an easy solution through UITextField which allows me to set the .autoSize which is great! However, now I'm trying to "style" (simply adjust font and font size) of the UITextField but it seems that I have to do it manually with '.htmlText' (which I'll gladly accept if that is the ONLY way).
I'm using the .text to set the value of the label.
My test case involves a HBox (I'm actually using a Grid but they should be the same and I've done testing on both):
I style the HBox and the style carries through to the UITextField. I don't believe this will work for me because I have other components inside that I need to style differently.
I've tried: UITextFormat and TextFormat (I see that the .htmlText being updated accordingly but the output doesn't update. Then I noticed that whenever I called hbox.addChild(myUITextField) it would override the .htmlText
I've tried setting the style with myUITextField.setStyle("fontSize", 20) before and/or after the call to addChild neither of which made an impact on the display as per what I noted above.
Changes are being made but they seem to be overrided when I add it to the display.
So what do I need to do in order to style the UITextField aside from manually setting it along with my contents in .htmlText? Solutions not using UITextField is fine as long as there is some easy way of not truncating the text.
EDIT: I want to just do textField.setStyle('fontSize', 20) and expect that every time I change the text, I wouldn't need to use HTML to go with it (so I can just do textField.text = 'something else' and expect that it will still have a font size of 20). This is what I meant by not using .htmlText (sorry if I wasn't clear before).
2nd EDIT: I guess I should present the whole issue and maybe that'll clarify what I did wrong or couldn't achieve.
My intent is to have a Grid and add text into it. I do not want it to wrap or scroll so I add it to the next row in the Grid when the current row's children total width exceeds some number. In order to add it to the next row, I need to be able to calculate the width of the text. I would like to be able to style that text individually based on cases and there might be other components (like a TextInput). Essentially what I'm trying to accomplish is "Fill in the Blank".
I've included code to show what I'm currently doing and it works somewhat. It might be un-related to the original issue of styling but I can't figure out how to adjust the distance between each UITextField but aside from that this fits what I would like to accomplish. Relevant to the question is: I would like to change the way I style each UITextField (currently setting .htmlText) into something a bit straightforward though like I previously mentioned I'll gladly accept using .htmlText if that's the only solution.
So I have a Grid with x Rows in it and in each row, I have exactly one GridItem. Based on the input, I add UITextField and TextInput into the GridItem going on to the next GridItem when necessary. If you have a better way of doing so then that would be better but I guess what I really want is to find a different way of styling.
Also another problem, I'm not sure of the exact way to add a TextField into the display. I tried:
var t : TextField = new TextField();
t.text = "I'm a TextField";
hBox.addChild(t); // doesn't work
//this.addChild(t); // doesn't work either
But I get the following error:
TypeError: Error #1034: Type Coercion failed: cannot convert flash.text::TextField#172c8f9 to mx.core.IUIComponent.
Here's what I have that's working.
private function styleQuestionString(str : String) : String {
return '<FONT leading="1" face="verdana" size="20">' + str + '</FONT>';
}
private function loadQuestion(str : String) : void {
/* Split the string */
var tmp : Array = str.split("_");
/* Track the current width of the GridItem */
var curWidth : int = 0;
/* Display components that we will add */
var txtField : UITextField = null;
var txtInput : TextInput = null;
/* Track the current GridItem */
var curGridItem : GridItem = null;
/* Track the GridItem we can use */
var gridItemAC : ArrayCollection = new ArrayCollection();
var i : int = 0;
/* Grab the first GridItem from each GridRow of Grid */
var tmpChildArray : Array = questionGrid.getChildren();
for (i = 0; i < tmpChildArray.length; i++) {
gridItemAC.addItem((tmpChildArray[i] as GridRow).getChildAt(0));
}
curGridItem = gridItemAC[0];
gridItemAC.removeItemAt(0);
/* Used to set the tab index of the TextInput */
var txtInputCounter : int = 1;
var txtFieldFormat : UITextFormat = new UITextFormat(this.systemManager);
txtFieldFormat.leading = "1";
//var txtFieldFormat : TextFormat = new TextFormat();
//txtFieldFormat.size = 20;
/* Proper Order
txtField = new UITextField();
txtField.text = tmp[curItem];
txtField.autoSize = TextFieldAutoSize.LEFT;
txtField.setTextFormat(txtFieldFormat);
*/
var txtLineMetrics : TextLineMetrics = null;
var tmpArray : Array = null;
curGridItem.setStyle("leading", "1");
var displayObj : DisplayObject = null;
for (var curItem : int= 0; curItem < tmp.length; curItem++) {
/* Using UITextField because it can be auto-sized! */
/** CORRECT BLOCK (ver 1)
txtField = new UITextField();
txtField.text = tmp[curItem];
txtField.autoSize = TextFieldAutoSize.LEFT;
txtField.setTextFormat(txtFieldFormat);
***/
tmpArray = (tmp[curItem] as String).split(" ");
for (i = 0; i < tmpArray.length; i++) {
if (tmpArray[i] as String != "") {
txtField = new UITextField();
txtField.htmlText = styleQuestionString(tmpArray[i] as String);
//txtField.setTextFormat(txtFieldFormat); // No impact on output
txtLineMetrics = curGridItem.measureHTMLText(txtField.htmlText);
curWidth += txtLineMetrics.width + 2;
if (curWidth >= 670) {
curGridItem = gridItemAC[0];
curGridItem.setStyle("leading", "1");
if (gridItemAC.length != 1) {
gridItemAC.removeItemAt(0);
}
// TODO Configure the proper gap distance
curWidth = txtLineMetrics.width + 2;
}
displayObj = curGridItem.addChild(txtField);
}
}
//txtField.setColor(0xFF0000); // WORKS
if (curItem != tmp.length - 1) {
txtInput = new TextInput();
txtInput.tabIndex = txtInputCounter;
txtInput.setStyle("fontSize", 12);
txtInputCounter++;
txtInput.setStyle("textAlign", "center");
txtInput.width = TEXT_INPUT_WIDTH;
curWidth += TEXT_INPUT_WIDTH;
if (curWidth >= 670) {
curGridItem = gridItemAC[0];
if (gridItemAC.length != 1) {
gridItemAC.removeItemAt(0);
}
// TODO Decide if we need to add a buffer
curWidth = TEXT_INPUT_WIDTH + 2;
}
curGridItem.addChild(txtInput);
txtInputAC.addItem(txtInput);
/* Adds event listener so that we can perform dragging into the TextInput */
txtInput.addEventListener(DragEvent.DRAG_ENTER, dragEnterHandler);
txtInput.addEventListener(DragEvent.DRAG_DROP, dragDropHandler);
txtInput.addEventListener(DragEvent.DRAG_EXIT, dragExitHandler);
}
/* Add event so that this label can be dragged */
//txtField.addEventListener(MouseEvent.MOUSE_MOVE, dragThisLabel(event, txtField.text));
}
}
After about 8 hours of searching for a solution to what would seem to be such a simple issue I FINALLY stumbled on your posts here... Thankyou!!!
I have been stumbling around trying to get TextField to work and had no Joy, Label was fine, but limited formatting, and I need to be able to use embedded fonts and rotate. After reading the above this finally worked for me:
var myFormat:TextFormat = new TextFormat();
myFormat.align = "center";
myFormat.font = "myFont";
myFormat.size = 14;
myFormat.color = 0xFFFFFF;
var newTxt:UITextField = new UITextField();
newTxt.text = "HELLO";
addChild(newTxt);
newTxt.validateNow();
newTxt.setTextFormat(myFormat);
The order of addChild before the final 2 steps was critical! (myFont is an embedded font I am using).
One again... a thousand thankyou's...
John
EDIT BASED ON THE ASKERS FEEDBACK:
I didn't realize you wanted to just apply one style to the whole textfield, I thought you wanted to style individual parts. This is even simpler for you, won't give you any trouble at all :)
var textFormat: TextFormat = new TextFormat("Arial", 12, 0xFF0000);
myText.setTextFormat(textFormat);
Be aware that this sets the style to the text that is in the TextField, not necessarily future text you put in. So have your text in the field before you call setTextFormat, and set it again every time you change it just to be sure it stays.
It's probably best if you use a normal TextField as opposed to the component. If you still want the component you may need to call textArea.validateNow() to get it to update with the new style (not 100% sure on that one though) Adobe components are notoriously bad, and should be avoided. :(
To see all available options on the TextFormat object see here
END EDIT ---------
This is easy enough to just do with CSS in a normal old TextField.
var myCSS: String = "Have some CSS here, probably from a loaded file";
var myHTML: String = "Have your HTML text here, and have it use the CSS styles";
// assuming your textfield's name is myText
var styleSheet: StyleSheet = new StyleSheet();
styleSheet.parseCSS(myCSS);
myText.autoSize = TextFieldAutoSize.LEFT;
myText.styleSheet = styleSheet;
myText.htmlText = myHTML;
Supported HTML tags can be found here
Supported CSS can be found here
The reason you have a problem adding Textfield to containers is that it doesn't implement the IUIComponent interface. You need to use UITextField if you want to add it. However, that's presenting me with my own styling issues that brought me to this question.
A few things I know:
TextField is styled using the TextFormat definition, and applying it to the textfield. As Bryan said, order matters.
setStyle does nothing on IUITextField, and the TextFormat method doesn't seem to work the same as in normal TextFields. (Edit #2: Ahah. You need to override the "validateNow" function on UITextFields to use the setTextFormat function)
To autosize a TextArea, you need to do something like this (inheriting from TextArea):
import mx.core.mx_internal;
use namespace mx_internal;
...
super.mx_internal::getTextField().autoSize = TextFieldAutoSize.LEFT;
this.height = super.mx_internal::getTextField().height;
Found this code on, I think, on StackOverflow a while back. Apologies to the original author. But the idea is that you need to access the "mx_internal" raw textfield.
Text and TextArea have wrapping options. (Label does not). So if you set the explicit width of a Text object, you might be able to size using the measuredHeight option and avoid truncation.
(edit: That was #4, but stackoverflow parsed it into a 1...)

Resources