flex 4.6 add or change element name when using addElement() - apache-flex

flex 4.6
I am using addElement as below. I note however that when inspecting the element, the name of the element is suffixed with a number, so the loaded element name of newMod becomes newMod10 (number is variable). If I want to then removeElement() I have no idea of what the correct getChildByName() would be, so getChildByName("newMod") fails.
So my Q's are
how do i addElement() with a unique name
how do find the name of the element I just added so I can reference by the nameXX
thx
Art
/* load module */
/* creationComplete="loadNewMod('modToLoad','A' )
public function loadNewMod(modName,evtTyp):void {
info = ModuleManager.getModule(modName);
var self:Object = this;
var meh = "modEventHandler"+(evtTyp);
info.addEventListener(ModuleEvent.READY, function(e:ModuleEvent){
self[meh](e)
});
info.load(null, null, null, moduleFactory);
}
private function modEventHandlerA(e:ModuleEvent):void {
vg1.addElement(info.factory.create() as IVisualElement);
}
<s:Group id="vg1" horizontalCenter="0" verticalCenter="0">
<s:Label id="newLabel" />
</s:Group>
[EDIT]
by breaking out the function I have added an ID that seems to work
private function modEventHandlerA(e:ModuleEvent,fcall):void {
var newID = info.factory.create();
newID.name = "myElem";
vg1.addElement(hh as IVisualElement);
}

Best way is likely to attach a name property to the object and do a for loop. It's inefficient, but the ID label doesn't seem to work properly when setting it in AS3.
info.name = "info1";
for ( var i:Number = 0; i < vg1.numElements; i++ ) {
if ( ( vg1.getElementAt(i) as UIComponent).name == "info1" ) {
vg1.removeElementAt(i);
break;
}
}
I didn't check to see if info would have the name property, but that would do the trick. Alternatively, you could use the exact same method with the id tag, except use indexOf("info1") >= 0, instead of .name == "info1"

Related

ng-grid How to set separate style for last row

I am trying to display some aggregate value (like total) in the last row of an ng-grid. The style and css class of the last row needs to be different than the other cells in that column. How to acheive this?
The cellTemplate in a column definition applies to all cells in that column, but in my case I need to have a different style for the last row in that column. Can anyone please suggest me a solution.
Thanks
Sudipta
I was able to add a class to the last row through a plugin:
function ngGridAddClassToLastRow(className) {
var self = this;
self.grid = null;
self.scope = null;
self.init = function (scope, grid, services) {
self.domUtilityService = services.DomUtilityService;
self.grid = grid;
self.scope = scope;
var addClass = function () {
var lastRow = self.scope.renderedRows[self.scope.renderedRows.length - 1];
lastRow.elm[0].className = lastRow.elm[0].className + ' ' + className;
};
self.scope.$watch(grid.config.data, addClass);
};
}
And with this added to the gridOptions:
...
plugins: [new ngGridAddClassToLastRow('<some class name>'),
...
And of course add some css, e.g. in my case:
.lastRow {
border-bottom: 0px;
}
That worked for me. I cannot say for certain that is the way to go since, needless to say, i'm a noob with Angular and ngGrid. I've constructed the plugin from flexible height plugin.
You can set a special property "isLast" (or however you like to name it) of the item that should be displayed in the last row. This item can be accessed through row.entity.isLast.
... somewhere in your controller ....
$scope.getRowClass = function(row) {
return row.entity.isLast === true ? 'lastRow' : '';
}
... somewhere inside the gridOptions ...
rowTemplate: '<div ng-style="{ \'cursor\': row.cursor }" ng-repeat="col in renderedColumns" ng-class="[col.colIndex(), getRowClass(row)]" class="ngCell {{col.cellClass}}">....</div>'
Based on the .lastRow class you could define a custom style for the last grid row.

adding tooltip to datagrid headers in dojo

I have a dojo datagrid which is poulated dynamically. I want to add tooltip to table headers of this datagrid. How can i do that?My datagrid simply has the structure of table and table headers. the fields get populated dynamically.
Thanks,
Sreenivas
Easiest Way
The easiest way, (Without overriding the template) would be to add a domNode to your layout header definition. So for example, when you are setting the "name" for your column in the layout, you can have something like ...
var layout = [
{
cells: [
{
name:"<i id="sometooltip" class='icon-large icon-edit'></i> Col",
field: "_item",
formatter: lang.hitch( this, this.formatter )
}
]
}];
What you then want to do is in your formatter, you want to check to see if "sometooltip" has be initialized as a tooltip, and do your connect.. You can use any tooltip.. not just dijit.Tooltip.
There are a few words of caution though. Because the formatter will run every time there is a redraw on your grid, you might want to think up better ways of creating your tooltip. For instance, you might want to add it to onGridRowHeaderHover, or you might want to just use CSS3 and use [title] attribute to create a CSS3 header.
Also. You can't just create the tooltip once, because the header is constantly rebuilt every redraw/change of data.
The Correct Way
The correct way would be to override the Grid template for the header, and include your tooltip in there. You would then extend the header equivalent of onStyleRow (which I can't remember), but basically the method that places the headers, and create your tooltip then.
I would definitely use the second option by overriding the template. Because otherwise you will find the grid glitchy.
For a pre-AMD Dojo version this is the monkey patch that we included in our globally scoped javascript resource. My other answer was after we switched to an AMD Dojo version.
// HeaderBuilder.generateHtml
// If showTooltips is true, the header contents will be used as the tooltip text.
var old_HeaderBuilder_generateHtml = dojox.grid._HeaderBuilder.prototype.generateHtml;
dojox.grid._HeaderBuilder.prototype.generateHtml = function(inGetValue, inValue){
var html = this.getTableArray(), cells = this.view.structure.cells;
dojox.grid.util.fire(this.view, "onBeforeRow", [-1, cells]);
for(var j=0, row; (row=cells[j]); j++){
if(row.hidden){
continue;
}
html.push(!row.invisible ? '<tr>' : '<tr class="dojoxGridInvisible">');
for(var i=0, cell, markup; (cell=row[i]); i++){
cell.customClasses = [];
cell.customStyles = [];
if(this.view.simpleStructure){
if(cell.headerClasses){
if(cell.headerClasses.indexOf('dojoDndItem') == -1){
cell.headerClasses += ' dojoDndItem';
}
}else{
cell.headerClasses = 'dojoDndItem';
}
if(cell.attrs){
if(cell.attrs.indexOf("dndType='gridColumn_") == -1){
cell.attrs += " dndType='gridColumn_" + this.grid.id + "'";
}
}else{
cell.attrs = "dndType='gridColumn_" + this.grid.id + "'";
}
}
markup = this.generateCellMarkup(cell, cell.headerStyles, cell.headerClasses, true);
// content
markup[5] = (inValue != undefined ? inValue : inGetValue(cell));
// set the tooltip for this header to the same name as the header itself
try {
markup[5] = markup[5].replace("class","title='"+cell.name+"' class");
} catch(e) {
console.debug(e);
}
// styles
markup[3] = cell.customStyles.join(';');
// classes
markup[1] = cell.customClasses.join(' '); //(cell.customClasses ? ' ' + cell.customClasses : '');
html.push(markup.join(''));
}
html.push('</tr>');
}
html.push('</table>');
return html.join('');
};
I had a similar requirement. I wanted each DataGrid column header to use the name given to the column as the tooltip since our DataGrids weren't always showing the full column name due to the columns' widths sometimes being squeezed. I added a monkey patch (below) that is done with an AMD Dojo version:
require(
[
"dojo/dom",
"dojox/grid/DataGrid",
"dijit/_Widget",
"dijit/form/FilteringSelect",
"dijit/form/MultiSelect",
"dijit/layout/ContentPane",
"dijit/layout/TabContainer",
"dojox/grid/_Grid",
"dijit/MenuItem",
"dijit/MenuSeparator",
"dojox/grid/_Builder",
"dojox/grid/cells/_base",
"dojox/grid/util",
"dojo/parser",
"dojo/_base/array",
"dojo/_base/lang",
"dojo/ready",
"dojo/query",
"dijit/registry",
],
function(dom, dojox_grid_DataGrid, dijit__Widget, dijit_form_FilteringSelect,
dijit_form_MultiSelect, dijit_layout_ContentPane, dijit_layout_TabContainer,
dojox_grid__Grid, MenuItem, MenuSeparator, dojox_grid__Builder,
dojox_grid_cells__Base, dojox_grid_util,
parser, array, dojoLang, ready, dojoQuery, registry) {
var old_HeaderBuilder_generateHtml = dojox_grid__Builder._HeaderBuilder.prototype.generateHtml;
dojox_grid__Builder._HeaderBuilder.prototype.generateHtml = function(inGetValue, inValue){
var html = this.getTableArray(), cells = this.view.structure.cells;
dojox_grid_util.fire(this.view, "onBeforeRow", [-1, cells]);
for(var j=0, row; (row=cells[j]); j++){
if(row.hidden){
continue;
}
html.push(!row.invisible ? '<tr>' : '<tr class="dojoxGridInvisible">');
for(var i=0, cell, markup; (cell=row[i]); i++){
cell.customClasses = [];
cell.customStyles = [];
if(this.view.simpleStructure){
if(cell.headerClasses){
if(cell.headerClasses.indexOf('dojoDndItem') == -1){
cell.headerClasses += ' dojoDndItem';
}
}else{
cell.headerClasses = 'dojoDndItem';
}
if(cell.attrs){
if(cell.attrs.indexOf("dndType='gridColumn_") == -1){
cell.attrs += " dndType='gridColumn_" + this.grid.id + "'";
}
}else{
cell.attrs = "dndType='gridColumn_" + this.grid.id + "'";
}
}
markup = this.generateCellMarkup(cell, cell.headerStyles, cell.headerClasses, true);
// content
markup[5] = (inValue != undefined ? inValue : inGetValue(cell));
// set the tooltip for this header to the same name as the header itself
markup[5] = markup[5].replace("class","title='"+cell.name+"' class");
// styles
markup[3] = cell.customStyles.join(';');
// classes
markup[1] = cell.customClasses.join(' '); //(cell.customClasses ? ' ' + cell.customClasses : '');
html.push(markup.join(''));
}
html.push('</tr>');
}
html.push('</table>');
return html.join('');
};
}
);
Note that if there's any chance that any markup may be added to the cell.name then you'll need to add a condition that will somehow extract just the text from it to be the tooltip, or somehow generate a tooltip that won't throw a rendering error, or avoid setting a tooltip altogether for that column.

Selecting MXML siblings with actionscript, like javascript?

I'm trying to get the sibling of an mxml tag similar to the way siblings are selected in javascript. Is this possible in Actionscript?
For example, when I click the TextArea with id textarea1, I need it to tell me that the sibling has an id of rect1 so I can do further processing to it.
<s:Group>
<s:TextArea id="textarea1" click="getSibling(event)" />
<s:Rect id="rect1" />
</s:Group>
Assuming Group, TextArea and Rect are UIComponents, I think this should work:
private function getSibling(e:Event):void {
var parent:UIComponent = e.currentTarget.parent;
if(parent) {
var len:int = parent.numChildren;
var child:UIComponent;
for(var i:int = 0; i < len; i++) {
child = parent.getChildAt(i) as UIComponent;
if(child && child != e.currentTarget) {
trace(child.id);
}
}
}
}
My initial thought here is to access the parent and then retrieve a list of children within it.
function getSibling(e:Event):void {
//get an array of children from the parent.
var children:Array = e.target.parent.getChildren();
//process children as you wish...
}
This was discussed with respect to Javascript here.
Hope this helps.
Nick
nickgs.com
As far as I know there is no way to do this. However, both textarea1 and rect1 are children of the Group. If you give the group an ID you should be able to loop over all the children to find all the siblings of the TextArea.
In Flex 3, you'd use a for loop, numChildren, and getChildAt. I suspect in Flex 4 it would be similar.

Actionscript flex: Converting # colors to uint

I'm working with several components that take color as a uint, but the colors I have are in the format of "#161616". I'm not sure what the relation between the 2 types of colors are or how to go from one to another.
It doesn't have to be an actionscript solution. I have only a small number of these colors, so can be done manually too.
var color:uint = 0x161616;
Or, to convert them programmatically:
var s:String = "#161616";
var color:uint = uint("0x" + s.substr(1));
Be aware that stylesheets in Flex want the color values in the form #FFFFFF ... NOT 0xFFFFFF. MXML element style properties don't care. Although when you start writing something like:
<mx:VBox backgroundColor="
the Intellisense prompts you for a uint value; if you go ahead and complete it like so
<mx:VBox backgroundColor="#FFFFFF"></VBox>
it will still make your backgroundColor the same as if you had written
<mx:VBox backgroundColor="0xFFFFFF"></VBox>
Here you are 2 of my utils functions:
public static function convertUintToString( color:uint ):String {
return color.toString(16);
}
public static function convertStringToUint(value:String, mask:String):uint {
var colorString:String = "0x" + value;
var colorUint:uint = mx.core.Singleton.getInstance("mx.styles::IStyleManager2").getColorName( colorString );
return colorUint;
}
the correct way is by using StyleManager.getColorName()
see the full documentation
var i : uint = uint("0x161616");

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