I hope to write a function PrintVars() that is able to print the variables altogether with their names. e.g.:
int var1 = 1;
bool var2 = True;
int var3 = 2;
PrintVars( var1, var2, var3 );
The expected output to the console is:
var1=1
var2=true
var3=2
The difficulty here is to
Get the variable name;
passing parameters of various types to the function.
Is there a way to achieve 1 and 2?
Neither 1) nor 2)
as MQL4 is a strong typed, compiled language.
Other possibilities to escape from this language syntax constraint ?
One may design a middle-ware tool for doing this, either locally, inside MQL4 or externally, via a messaging based distributed system ( having a remote terminal window ).
MQL4-based polymorphism is somewhat easier with class-based calling interface, while the efforts would be immense if such module ought be elaborated for some production grade deployment.
Somewhat clumsy sketch of the approach follows:
- create your vars as a properly configured polymorphic instance of aNamedVARIABLE class
- create a printing function, receiving a long list ( or a placeholder ( string &NameValueARRAY[] ) for a string array[][2]; initialised with "" and pre-filled with Name-Value pairs by .getName2PRINT(), resp. .getValue2PRINT() public methods ) of string variables to print, unless they are left as just initialised == ""
string printFun( const string N1 = "",
const string V1 = "",
const string N2 = "",
const string V2 = "",
...
..
.
){ string aPrintSTRING = "";
aPrintSTRING += ( ( N1 != "" ) ? ( N1 + " = " + V1 ) : "" );
aPrintSTRING += ( ( N2 != "" ) ? ( N2 + " = " + V2 ) : "" );
aPrintSTRING += ( ( N3 != "" ) ? ( N3 + " = " + V3 ) : "" );
...
..
.
return( aPrintSTRING );
}
...
..
.
print( printFun( aNamedVAR1.getName2PRINT(), aNamedVAR1.getValue2PRINT(),
aNamedVAR2.getName2PRINT(), aNamedVAR2.getValue2PRINT(),
aNamedVAR3.getName2PRINT(), aNamedVAR3.getValue2PRINT(),
aNamedVAR4.getName2PRINT(), aNamedVAR4.getValue2PRINT()
)
);
class aNamedVARIABLE{
private:
string aNameAsSTRING = "";
bool aValueAsBOOL = False;
bool aValueAsBOOL_[] = {};
int aValueAsINT = EMPTY_VALUE;
int aValueAsINT_[] = {};
string aValueAsSTR = "";
string aValueAsSTR_[] = {};
...
..
.
isBoolean = False;
isInteger = False;
isShort = False;
isUint = False;
isUchar = False;
isChar = False;
isString = False;
isDouble = False;
isDatetime = False;
isColor = False;
isClass = False;
isEnum = False;
isStruct = False;
isBooleanArr = False;
isIntegerArr = False;
isUintArr = False;
isShortArr = False;
isUintArr = False;
isUcharArr = False;
isDoubleArr = False;
isDatetimeArr = False;
isColorArr = False;
public:
aNamedVARIABLE() {}; // default constructor
aNamedVARIABLE( const string aName,
const bool aBool ){ aNamedVARIABLE::setBool( aBool );
aNamedVARIABLE::setName( aName );
}
aNamedVARIABLE( const string aName,
const int anInt ){ aNamedVARIABLE::setInt( anInt );
aNamedVARIABLE::setName( aName );
}
...
..
.
getName2PRINT() { return( this.aNameAsSTRING );
}
getValue2PRINT() { if ( this.isBoolean ) return( this.aValueAsBOOL ? "True" : "False" );
if ( this.isInteger ) return( str( this.aValueAsINT ) );
...
..
.
}
}
Related
We have logging tables in our Oracle database that show old and new values when changes are made to certain data fields. One of these fields is a SQL_TEXT field (for running reports via dynamic SQL).
For example:
CREATE TABLE schema1.rpt_sql_log (
rpt_id NUMBER(9), -- surrogate key of report
chg_id NUMBER(9), -- change number of query for this rpt_id
old_sql_txt VARCHAR2(2000), -- old report SQL statement
new_sql_txt VARCHAR2(2000) -- new report SQL statement
);
INSERT INTO schema1.rpt_sql_log VALUES (
1,
2,
'SELECT emp_id, dept_id, salary FROM emp ORDER BY emp_id',
'SELECT emp_id, dept_nm, salary FROM emp e INNER JOIN dept d ON e.dept_id = d.dept_id ORDER BY emp_id'
);
COMMIT;
Our analyst ordinarily would export these fields to 2 separate text files and then open them in BeyondCompare, UltraCompare, or WinMerge. They have asked if it is possible to do this textual comparison/diff directly in a query (i.e., is there a built-in diff function). To the best of my knowledge, no such built-in function exists.
My question is this: is there already a "diff-like" function available online that mimics the output of a Myers diff algorithm (i.e., something that highlights or <tag>s the changes, as one might see in Git or TortoiseSVN)
To my knowledge, there is no such built-in PL/SQL function to do so.
However, using this JavaScript code which describes a diff function that adds and tags and the MultiLingual Engine capabilities of the 21c Oracle database release (which allows you to create stored procedures that can execute JavaScript code); you could go with such an approach:
set define off
set serveroutput on size unlimited
DECLARE
ctx DBMS_MLE.context_handle_t := DBMS_MLE.create_context();
codeSnippet clob ;
result clob;
BEGIN
codeSnippet := q'~
/*
* Javascript Diff Algorithm
* By John Resig (http://ejohn.org/)
* Modified by Chu Alan "sprite"
*
* Released under the MIT license.
*
* More Info:
* http://ejohn.org/projects/javascript-diff-algorithm/
*/
function escape(s) {
var n = s;
n = n.replace(/&/g, "&");
n = n.replace(/</g, "<");
n = n.replace(/>/g, ">");
n = n.replace(/"/g, """);
return n;
}
function diffString( o, n ) {
o = o.replace(/\s+$/, '');
n = n.replace(/\s+$/, '');
var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/) );
var str = "";
var oSpace = o.match(/\s+/g);
if (oSpace == null) {
oSpace = ["\n"];
} else {
oSpace.push("\n");
}
var nSpace = n.match(/\s+/g);
if (nSpace == null) {
nSpace = ["\n"];
} else {
nSpace.push("\n");
}
if (out.n.length == 0) {
for (var i = 0; i < out.o.length; i++) {
str += '<del>' + escape(out.o[i]) + oSpace[i] + "</del>";
}
} else {
if (out.n[0].text == null) {
for (n = 0; n < out.o.length && out.o[n].text == null; n++) {
str += '<del>' + escape(out.o[n]) + oSpace[n] + "</del>";
}
}
for ( var i = 0; i < out.n.length; i++ ) {
if (out.n[i].text == null) {
str += '<ins>' + escape(out.n[i]) + nSpace[i] + "</ins>";
} else {
var pre = "";
for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
pre += '<del>' + escape(out.o[n]) + oSpace[n] + "</del>";
}
str += " " + out.n[i].text + nSpace[i] + pre;
}
}
}
return str;
}
function randomColor() {
return "rgb(" + (Math.random() * 100) + "%, " +
(Math.random() * 100) + "%, " +
(Math.random() * 100) + "%)";
}
function diffString2( o, n ) {
o = o.replace(/\s+$/, '');
n = n.replace(/\s+$/, '');
var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/) );
var oSpace = o.match(/\s+/g);
if (oSpace == null) {
oSpace = ["\n"];
} else {
oSpace.push("\n");
}
var nSpace = n.match(/\s+/g);
if (nSpace == null) {
nSpace = ["\n"];
} else {
nSpace.push("\n");
}
var os = "";
var colors = new Array();
for (var i = 0; i < out.o.length; i++) {
colors[i] = randomColor();
if (out.o[i].text != null) {
os += '<span style="background-color: ' +colors[i]+ '">' +
escape(out.o[i].text) + oSpace[i] + "</span>";
} else {
os += "<del>" + escape(out.o[i]) + oSpace[i] + "</del>";
}
}
var ns = "";
for (var i = 0; i < out.n.length; i++) {
if (out.n[i].text != null) {
ns += '<span style="background-color: ' +colors[out.n[i].row]+ '">' +
escape(out.n[i].text) + nSpace[i] + "</span>";
} else {
ns += "<ins>" + escape(out.n[i]) + nSpace[i] + "</ins>";
}
}
return { o : os , n : ns };
}
function diff( o, n ) {
var ns = new Object();
var os = new Object();
for ( var i = 0; i < n.length; i++ ) {
if ( ns[ n[i] ] == null )
ns[ n[i] ] = { rows: new Array(), o: null };
ns[ n[i] ].rows.push( i );
}
for ( var i = 0; i < o.length; i++ ) {
if ( os[ o[i] ] == null )
os[ o[i] ] = { rows: new Array(), n: null };
os[ o[i] ].rows.push( i );
}
for ( var i in ns ) {
if ( ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1 ) {
n[ ns[i].rows[0] ] = { text: n[ ns[i].rows[0] ], row: os[i].rows[0] };
o[ os[i].rows[0] ] = { text: o[ os[i].rows[0] ], row: ns[i].rows[0] };
}
}
for ( var i = 0; i < n.length - 1; i++ ) {
if ( n[i].text != null && n[i+1].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
n[i+1] == o[ n[i].row + 1 ] ) {
n[i+1] = { text: n[i+1], row: n[i].row + 1 };
o[n[i].row+1] = { text: o[n[i].row+1], row: i + 1 };
}
}
for ( var i = n.length - 1; i > 0; i-- ) {
if ( n[i].text != null && n[i-1].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
n[i-1] == o[ n[i].row - 1 ] ) {
n[i-1] = { text: n[i-1], row: n[i].row - 1 };
o[n[i].row-1] = { text: o[n[i].row-1], row: i - 1 };
}
}
return { o: o, n: n };
}
var bindings = require("mle-js-bindings");
var string1 = bindings.importValue("string1");
var string2 = bindings.importValue("string2");
bindings.exportValue("result", diffString(string1,string2)); ~';
dbms_mle.export_to_mle(ctx, 'string1', 'The red brown fox jumped over the rolling log.');
dbms_mle.export_to_mle(ctx, 'string2', 'The brown spotted fox leaped over the rolling log');
DBMS_MLE.eval(ctx, 'JAVASCRIPT', codeSnippet);
DBMS_MLE.import_from_mle(ctx, 'result', result);
DBMS_OUTPUT.put_line(result);
DBMS_MLE.drop_context(ctx);
END;
/
Running the code above using SQLcl, gives me:
The <del>red </del> brown <ins>spotted </ins> fox <del>jumped </del><ins>leaped
</ins> over the rolling <del>log.
</del><ins>log
</ins>
PL/SQL procedure successfully completed.
SQL>
Using the following MWE:
import controlP5.*;
import java.util.*;
ControlP5 cp5;
void setup() {
size(400, 400);
cp5 = new ControlP5(this);
List l = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h");
/* add a ScrollableList, by default it behaves like a DropdownList */
cp5.addScrollableList("dropdown")
.setPosition(100, 100)
.setSize(200, 100)
.setBarHeight(20)
.setItemHeight(20)
.addItems(l)
// .setType(ScrollableList.LIST) // currently supported DROPDOWN and LIST
;
}
void draw() {
background(240);
}
How can I change the font color of each list entry separately? I assume I'll have to use a for loop of some kind like the following
for (int i =0; i < myarray.length; i++){
dropdown.setColorActive(elementDetermine(myarray[i]));
}
Where elementDetermine() takes an integer and returns a color. Unfortunately, when I run this loop in either the setup or the draw function, the dropdown list doesn't change without error message.
Unfortunately there's no easy readily available method to change the font color of each list entry separately.
As you can see in the documentation the available methods access the main caption which applies to all items.
In fact, the same Label component is re-used accross all list items and simply re-rendered once per item (changing current text/colours) as you can see in the source code
If you really really need to change the font color you can, but that will be quite a few OOP hoops to jump through (since there is no array of Label instances per item):
you'd need to make a custom ControllerView< ScrollableList > to override it's display() method
for the custom display() to work the same as the original ScrollableList you need to pretty much replicate the super class
the ScrollableList super class has a bunch of private properties that can easily be accessed from the ScrollableListView class since it's part of ScrollableList, however in our case all those private / protected properties that need to be accessed in display() need to be accessible. To do this a ScrollableList subclass is implemenented (PopUpScrollableList) which mainly replicates it's superclass behaviours wherever those private/protected properties are used in display() and also makes them available.
Finally the custom scrollable list can have a color[] which can store the custom colours so they can be accessed and rendered in the overriden display() method:
import controlP5.*;
// used by the custom scrollable list view
import static controlP5.ControlP5.b;
import java.util.*;
ControlP5 cp5;
void setup() {
size(400, 400);
cp5 = new ControlP5(this);
List l = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h");
/* add a custom ScrollableList, by default it behaves like a DropdownList */
PopUpScrollableList dropdown = addPopUpScrollableList("dropdown");
dropdown.setPosition(100, 100)
.setSize(200, 100)
.setBarHeight(20)
.setItemHeight(20)
.addItems(l)
// .setType(ScrollableList.LIST) // currently supported DROPDOWN and LIST
;
// a list of (random) colourr: a colour per item
color[] textColors = new color[l.size()];
for(int i = 0 ; i < textColors.length; i++){
textColors[i] = color(255, random(255), random(255), random(255));
}
// set custom text colours: this is a bit hacky: normally you'd check if items.size() matches textColors.length, etc.
dropdown.textColors = textColors;
// set a custom view for the list
dropdown.setView(makeCustomScrollListView());
}
void draw() {
background(240);
}
// simply adds our custom scrollable list
PopUpScrollableList addPopUpScrollableList( final String theName ) {
PopUpScrollableList myController = new PopUpScrollableList(cp5, theName);
return myController;
}
ControllerView< ScrollableList > makeCustomScrollListView(){
// make an custom scrollable list view on the fly and access the fileds it needs
return new ControllerView< ScrollableList >() {
// tweaked version of https://github.com/sojamo/controlp5/blob/1f7cb649865eb8657495b5cfeddd0dbe85d70cac/src/controlP5/ScrollableList.java#L391
public void display( PGraphics g , ScrollableList c ) {
// setHeight( -200 ); /* UP */
PopUpScrollableList d = (PopUpScrollableList)c;
g.noStroke( );
if ( c.isBarVisible( ) ) {
boolean b = d.itemHover() == -1 && d.isInside() && !d.isDragged();
g.fill( b ? c.getColor( ).getForeground( ) : c.getColor( ).getBackground( ) );
g.rect( 0 , 0 , c.getWidth( ) , c.getBarHeight() );
g.pushMatrix( );
g.translate( c.getWidth( ) - 8 , c.getBarHeight() / 2 - 2 );
g.fill( c.getColor( ).getCaptionLabel( ) );
if ( c.isOpen( ) ) {
g.triangle( -3 , 0 , 3 , 0 , 0 , 3 );
} else {
g.triangle( -3 , 3 , 3 , 3 , 0 , 0 );
}
g.popMatrix( );
c.getCaptionLabel( ).draw( g , 4 , c.getBarHeight() / 2 );
}
if ( c.isOpen( ) ) {
int bar = ( c.isBarVisible( ) ? c.getBarHeight() : 0 );
int h = ( ( d.updateHeight( ) ) );
g.pushMatrix( );
// g.translate( 0 , - ( h + bar +
// c.itemSpacing ) ); /* UP */
g.fill( c.getBackgroundColor( ) );
g.rect( 0 , bar , c.getWidth( ) , h );
g.pushMatrix( );
g.translate( 0 , ( bar == 0 ? 0 : ( c.getBarHeight() + d.itemSpacing() ) ) );
/* draw visible items */
c.updateItemIndexOffset( );
int m0 = d.itemIndexOffset;
List items = c.getItems();
int m1 = items.size( ) > d.itemRange() ? ( d.itemIndexOffset + d.itemRange() ) : items.size( );
for ( int i = m0 ; i < m1 ; i++ ) {
Map< String , Object > item = (Map< String , Object >) items.get( i );
CColor itemColor = ( CColor ) item.get( "color" );
g.fill( ( b( item.get( "state" ) ) ) ? itemColor.getActive( ) : ( i == d.itemHover() ) ? ( c.isMousePressed() ? itemColor.getActive( ) : itemColor.getForeground( ) ) : itemColor.getBackground( ) );
float boxY = d.itemHeight() - 1;
g.rect( 0 , 0 , c.getWidth( ) , boxY );
Label label = c.getValueLabel( );
// finally set custom text colour
if(d.textColors != null){
label.setColor(d.textColors[i]);
}
label.set( item.get( "text" ).toString( ) ).draw( g , 4 , d.itemHeight() / 2 );
g.translate( 0 , d.itemHeight() );
}
g.popMatrix( );
if ( c.isInside() ) {
int m = items.size( ) - d.itemRange();
if ( m > 0 ) {
g.fill( c.getColor( ).getCaptionLabel( ) );
g.pushMatrix( );
int s = 4; /* spacing */
int s2 = s / 2;
g.translate( c.getWidth( ) - s , c.getBarHeight() );
int len = ( int ) PApplet.map( ( float ) Math.log( m * 10 ) , 0 , 10 , h , 0 );
int pos = ( int ) ( PApplet.map( d.itemIndexOffset , 0 , m , s2 , h - len - s2 ) );
g.rect( 0 , pos , s2 , len );
g.popMatrix( );
}
}
g.popMatrix( );
}
}
};
}
// a custom ScrollableList subclass: mainly it needs to expose properties the custom view (via setView()) can't access in display()
class PopUpScrollableList extends ScrollableList{
private int itemIndexOffset = 0;
private int _myType = DROPDOWN;
protected boolean isOpen = true;
public color[] textColors;
PopUpScrollableList(ControlP5 cp5, String name){
super(cp5, name);
println("custom PopUpScrollableList named " + name + " constructed");
}
public boolean isOpen( ) {
return isOpen;
}
public ScrollableList open( ) {
return setOpen( true );
}
public ScrollableList close( ) {
return setOpen( false );
}
public ScrollableList setOpen( boolean b ) {
isOpen = b;
return this;
}
public int itemHover(){
return itemHover;
}
public int itemSpacing(){
return 1;
}
public int itemRange(){
return itemRange;
}
public int itemHeight(){
return itemHeight;
}
public boolean isInside(){
return isInside;
}
public boolean isDragged(){
return isDragged;
}
public int barHeight(){
return barHeight;
}
protected int updateHeight( ) {
itemRange = ( PApplet.abs( getHeight( ) ) - ( isBarVisible( ) ? barHeight : 0 ) ) / itemHeight;
return itemHeight * ( items.size( ) < itemRange ? items.size( ) : itemRange );
}
public List< Map< String , Object > > items(){
return items;
}
#Override protected void onRelease( ) {
if ( !isDragged ) {
if ( getPointer( ).y( ) >= 0 && getPointer( ).y( ) <= barHeight ) {
setOpen( !isOpen( ) );
} else if ( isOpen ) {
double n = Math.floor( ( getPointer( ).y( ) - barHeight ) / itemHeight );
// n += itemRange; /* UP */
int index = ( int ) n + itemIndexOffset;
updateIndex( index );
}
}
}
private void updateIndex( int theIndex ) {
if ( theIndex >= items.size( ) ) {
return;
}
Map m = items.get( theIndex );
switch ( _myType ) {
case ( LIST ):
super.setValue( theIndex );
for ( Object o : items ) {
( ( Map ) o ).put( "state" , false );
}
m.put( "state" , !ControlP5.b( m.get( "state" ) ) );
break;
case ( DROPDOWN ):
super.setValue( theIndex );
setOpen( false );
getCaptionLabel( ).setText( ( m.get( "text" ).toString( ) ) );
break;
case ( CHECKBOX ):
m.put( "state" , !ControlP5.b( m.get( "state" ) ) );
break;
}
}
public ScrollableList setValue( float theValue ) {
updateIndex( ( int ) ( theValue ) );
return this;
}
#Override protected void onDrag( ) {
scroll( getPointer( ).dy( ) );
}
#Override protected void onScroll( int theValue ) {
scroll( theValue );
}
private void scroll( int theValue ) {
if ( isOpen() ) {
itemIndexOffset += theValue;
itemIndexOffset = ( int ) ( Math.floor( Math.max( 0 , Math.min( itemIndexOffset , items.size( ) - itemRange ) ) ) );
itemHover = -2;
}
}
#Override protected void onLeave( ) {
itemHover = -1;
}
#Override protected void onEnter( ) {
updateHover( );
}
#Override protected void onMove( ) {
updateHover( );
}
#Override protected void onEndDrag( ) {
updateHover( );
}
private void updateHover( ) {
if ( getPointer( ).y( ) > barHeight ) {
double n = Math.floor( ( getPointer( ).y( ) - barHeight ) / itemHeight );
itemHover = ( int ) ( itemIndexOffset + n );
} else {
itemHover = -1;
}
}
public void updateItemIndexOffset( ) {
int m1 = items.size( ) > itemRange ? ( itemIndexOffset + itemRange ) : items.size( );
int n = ( m1 - items.size( ) );
if ( n >= 0 ) {
itemIndexOffset -= n;
}
}
}
I want to add sorting for column in celltable with help of ListHandler. But it doesn't sort. I don't understand why it doesn't work. My code is based on GWT tutorial.
Please suggest me something.
Contract.java
public class Contract implements Serializable {
private int contId;
private String contOrgName;
//getters and setters...
}
Main.java
TextColumn<Contract> orgNameColumn = new TextColumn<Contract>() {
#Override
public String getValue(Contract contract) {
return contract.getcontOrgName();
}};
orgNameColumn.setSortable(true);
CellTable<Contract> tableContract = new CellTable<Contract>();
tableContract.addColumn(orgNameColumn, "OrgName");
ListDataProvider<Contract> contractDataProvider = new ListDataProvider<Contract>();
contractDataProvider.addDataDisplay(tableContract);
GetContractsServiceAsync getContractsService = GWT.create(GetContractsService.class);
getContractsService.getContracts(new AsyncCallback<List<Contract>>() {
public void onFailure(Throwable caught) {
// Show the RPC error message to the user
}
public void onSuccess(List<Contract> result) {
contractDataProvider.getList().clear();
contractDataProvider.getList().addAll(result);
ListHandler<Contract> columnSortHandler = new ListHandler<Contract>(result);
columnSortHandler.setComparator(orgNameColumn, new Comparator<Contract>() {
public int compare(Contract o1, Contract o2) {
if (o1 == o2) {
return 0;
}
if (o1 != null) {
return (o2 != null) ? o1.getcontOrgName().compareTo(o2.getcontOrgName()) : 1;
}
return -1;
}
});
tableContract.addColumnSortHandler(columnSortHandler);
table.getColumnSortList().push(orgNameColumn);
}
});
Hey I was also facing the same issue a long back..Then I got to know that the object reference id is different than the one I have added into table. Once i got the reason it was very easy to find the solution.
Also please register your ListHandler before adding column to CellTable.
Note the edit for your comment :
There is nothing wrong with the comparator. The problem is still same. It reflects the wrong the object in comparator compared to in CellTable.
Please try replace the code as below :
contractDataProvider.getList().addAll(result);
ListHandler<Contract> columnSortHandler = new ListHandler<Contract>(contractDataProvider.getList());
Try to move the creation of your columnSortHandler out of the onSuccess Method. Place it right after you created your column.
At the moment you are adding the results before you add the columnSortHandler. I think that is the wrong order.
i my case, i did my sorting like this:
private void sortColumn( List<CModel> list ) {
int count = listOfColumns.size(); //upon adding the columns, i have created a list that will hold all the columns
if ( list.size() <= 0 ) {
for ( int i = 0; i < count; i++ ) {
listOfColumns.get(i).setSortable( false );
}
} else {
for ( int i = 0; i < count; i++ ) {
sort( i );
dg.redrawHeaders();
}
}
}
private void sort(int i) {
String[] listColHead = { /** list of column headers */ };
Column<CModel,?> column = listCheckoutColumns.get( i );
final String valueToCompare = listColHead[i];
final ListDataProvider<CModel> dataProvider = new ListDataProvider<CModel>();
// Connect the table to the data provider
dataProvider.addDataDisplay( dg );
// Add the data to the data provider, which automatically pushes it to the widget
List<CModel> list = dataProvider.getList();
for ( CModel product : listCheckout ) {
list.add( product );
}
column.setSortable( true );
// Add a ColumnSortEvent.ListHandler to connect sorting to the List
ListHandler<CModel> columnSortHandler = new ListHandler<CModel>( list );
columnSortHandler.setComparator( column, new Comparator<CModel>() {
public int compare( CModel p1, CModel p2 ) {
if ( p1 == p2 ) {
return 0;
}
// Compare the columns.
if ( p1 != null ) {
if ( valueToCompare.equals( "code" ) ) {
return ( p2 != null ) ? p1.getFproductid().compareTo( p2.getFproductid() ) : 1;
}
else if ( valueToCompare.equals( "desc" ) ) {
return ( p2 != null ) ? p1.getFproduct_name().compareTo( p2.getFproduct_name() ) : 1;
}
else if ( valueToCompare.equals( "type" ) ) {
return ( p2 != null ) ?
uec.computeTypeLabel( p1 ).compareTo( uec.computeTypeLabel( p2 ) ) : 1;
}
else if ( valueToCompare.equals( "maxex" ) ) {
return ( p2 != null ) ? uec.exQtyLabel( p1 ).compareTo( uec.exQtyLabel( p2 ) ) : 1;
}
else if ( valueToCompare.equals( "unit" ) ) {
return ( p2 != null ) ? p1.getFuom().compareTo( p2.getFuom() ) : 1;
}
else if ( valueToCompare.equals( "status" ) ) {
return ( p2 != null ) ? uec.qtyLabel( p1 ).compareTo( uec.qtyLabel( p2 ) ) : 1;
}
else if ( valueToCompare.equals( "qty" ) ) {
return ( p2 != null ) ? Double.compare( p1.getFqty(), p2.getFqty() ) : 1;
}
else if ( valueToCompare.equals( "price" ) ) {
return ( p2 != null ) ? uec.extPriceLabel( p1 ).compareTo( uec.extPriceLabel( p2 ) ) : 1;
}
else if ( valueToCompare.equals( "total" ) ) {
return ( p2 != null ) ? Double.compare( p1.getFtotal_line(), p2.getFtotal_line() ) : 1;
}
}
return -1;
}
});
dg.addColumnSortHandler( columnSortHandler );
dg.getColumnSortList().push( column );
}
everytime, i'll set the data for my DataGrid list,
dgCheckout.redraw();
dgCheckout.setRowCount( lengthOfList, true );
dgCheckout.setRowData( 0, newList );
sortColumn( newList );
If I have a Backbone model who's defaults object looks like this:
defaults {
"id" : null
"name" : null,
"url" : null,
"admin" : {
"id" : null,
"email" : null
}
}
is there a recommended way to validate the presence of something like admin[id]? We've written a method that makes the attempt, but it keeps puking (especially on new model creation) on null values, or if data is fetched from our DB with null values that are expected to be required (we are laying this app on top of existing data).
Here's our method for validating the presence of required fields:
validatePresence = function(requiredAttrs, submittedAttrs, errorsArr) {
var regex = new RegExp(/[a-zA-Z0-9_]+|(?=\[\])/g),
attrStack = null,
val = null,
name = null;
for( var l = requiredAttrs.length; --l >= 0; ) {
attrStack = requiredAttrs[l].match(regex);
val = submittedAttrs[attrStack.shift()];
while(attrStack.length > 0) {
console.log(requiredAttrs[l]);
val = val[attrStack.shift()];
}
if( val === undefined ) { continue; }
name = requiredAttrs[l];
if( val === null || !val.length) {
if( !errorsArr[name] ) {
errorsArr[name] = [];
}
errorsArr[name].push("Oops, this can't be empty");
}
}
return errorsArr;
}
And here's the way we call it from within a BB model:
validate: function(attrs) {
var requiredAttributes = ["name","admin[id]"],
errors = {};
errors = validatePresence(requiredAttributes, attrs, errors);
}
That method likes to choke on things like "admin[id]". Any help is apprecaited.
If you're not dead set on the bracket notation for your required attributes, you could draw some inspiration from this Q&A to simplify your validation.
Let's add a helper method to _ to extract the value of a given attribute:
_.findprop = function(obj, path) {
var args = path.split('.'), i, l=args.length;
for (i=0; i<l; i++) {
if (!obj.hasOwnProperty(args[i]))
return;
obj = obj[args[i]];
}
return obj;
}
Your validate method can then be rewritten as:
validate: function(attrs) {
var requiredAttributes = ["name","admin.id"],
errors = {}, i, l, v, attr;
for (i=0, l=requiredAttributes.length; i<l; i++) {
attr = requiredAttributes[i];
v = _.findprop(attrs, attr);
//checks if the value is truthy, to be adapted to your needs
if (v) continue;
errors[attr] = errors[attr] || [];
errors[attr].push("Oops, this can't be empty");
}
return errors;
}
And a demo http://jsfiddle.net/FrtHb/2/
I wrote a small function that splits a number to commas but I have to run over the number too many times. Can you sugest me a better way to do this?
public static function getCommaString(value:Number):String {
var stringValue:String = value.toString();
if (stringValue.length <= 3) {
return stringValue;
}
var i:int = stringValue.length % 3;
if (i == 0) {
i = 3;
}
for (; i < stringValue.length; i += 4 ) {
var part1:String = stringValue.substr(0, i);
var part2:String = stringValue.substr(i, stringValue.length);
stringValue = part1.concat(",", part2);
}
return stringValue;
}
I put together a testing class that compares your solution and others, including a solution from this blog post and solutions from this related StackExchange question and formatted them in a consistent way for easy comparison:
package
{
public class CommaNumberSolutions
{
public static function commaify( input:Number ):String
{
var split:Array = input.toString().split( '.' ),
front:String = split[0],
back:String = ( split.length > 1 ) ? "." + split[1] : null,
n:int = input < 0 ? 2 : 1,
commas:int = Math.floor( (front.length - n) / 3 ),
i:int = 1;
for ( ; i <= commas; i++ )
{
n = front.length - (3 * i + i - 1);
front = front.slice( 0, n ) + "," + front.slice( n );
}
if ( back )
return front + back;
else
return front;
}
public static function getCommaString( input:Number ):String
{
var s:String = input.toString();
if ( s.length <= 3 )
return s;
var i:int = s.length % 3;
if ( i == 0 )
i = 3;
for ( ; i < s.length; i += 4 )
{
var part1:String = s.substr(0, i);
var part2:String = s.substr(i, s.length);
s = part1.concat(",", part2);
}
return s;
}
public static function formatNumber( input:Number ):String
{
var s:String = input.toString()
var result:String = ''
while ( s.length > 3 )
{
var chunk:String = s.substr(-3)
s = s.substr(0, s.length - 3)
result = ',' + chunk + result
}
if ( s.length > 0 )
result = s + result
return result
}
public static function commaCoder( input:Number ):String
{
var s:String = "";
var len:Number = input.toString().length;
for ( var i:int = 0; i < len; i++ )
{
if ( (len-i) % 3 == 0 && i != 0)
s += ",";
s += input.toString().charAt(i);
}
return s;
}
public static function regex1( input:Number ):String
{
return input.toString().replace( /-{0,1}(\d)(?=(\d\d\d)+$)/g, "$1," );
}
public static function regex2( input:Number ):String
{
return input.toString().replace( /-{0,1}\d{1,3}(?=(\d{3})+(?!\d))/g , "$&,")
}
public static function addCommas( input:Number ):String
{
var negative:String = "";
if ( input < 0 )
{
negative = "-";
input = Math.abs(input);
}
var s:String = input.toString();
var results:Array = s.split(/\./);
s = results[0];
if ( s.length > 3 )
{
var mod:Number = s.length % 3;
var output:String = s.substr(0, mod);
for ( var i:Number = mod; i < s.length; i += 3 )
{
output += ((mod == 0 && i == 0) ? "" : ",") + s.substr(i, 3);
}
if ( results.length > 1 )
{
if ( results[1].length == 1 )
return negative + output + "." + results[1] + "0";
else
return negative + output + "." + results[1];
}
else
return negative + output;
}
if ( results.length > 1 )
{
if ( results[1].length == 1 )
return negative + s + "." + results[1] + "0";
else
return negative + s + "." + results[1];
}
else
return negative + s;
}
}
}
You can see a more detailed analysis at my other answer but you can compare the compactness of each solution and weigh that against their accuracy and performance, however for the sake of brevity this solution is the most accurate and performant (though not the most compact):
public function commaify( input:Number ):String
{
var split:Array = input.toString().split( '.' ),
front:String = split[0],
back:String = ( split.length > 1 ) ? "." + split[1] : null,
n:int = input < 0 ? 2 : 1,
commas:int = Math.floor( (front.length - n) / 3 ),
i:int = 1;
for ( ; i <= commas; i++ )
{
n = front.length - (3 * i + i - 1);
front = front.slice( 0, n ) + "," + front.slice( n );
}
if ( back )
return front + back;
else
return front;
}