flex mx line chart datafunction - actionscript-3

I have a JSON service link that returns month as an Integer and a price as a Number which I display on an <mx:Linechart />.
Now, I don't want to display the month as an Integer instead as the string equivalent of the month value.
I have tried to create a datafunction like so
public function myDataFunction(series:LineSeries, item:Object, fieldName:String):Object {
var months:Array = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var my_date:Date = new Date();
if (fieldName == 'yValue')
return(item.price);
else if (fieldName == "xValue")
{
return((months[my_date.month]));
}
else
return null;
}
I would like to post reputations but i don't have enough reputations.
Anybody please help.
Thanks

To show months names in the horizontal axis, you need to assign labelFunction to it.
When declaring line chart, you specify horizontal axis like this:
<mx:Linechart>
<mx:horizontalAxis>
<mx:CategoryAxis categoryField="xValue"/>
</mx:horizontalAxis>
</mx:Linechart>
To modify values of horizontal axis, you need to specify labelFunction:
<mx:CategoryAxis categoryField="xValue" labelFunction="labelFunction"/>
labelFunction should look like this:
function labelFunction(categoryValue:Object, previousCategoryValue:Object, axis:CategoryAxis, categoryItem:Object):String {
return "label";
}
For more info see: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/charts/CategoryAxis.html#labelFunction

Related

Telerik MVC Chart - Bind to JSON

How do I bind a Telerik ASP.Net MVC Chart (not the Kendo for jQuery version ) to JSON? For example, I would like to bind the following chart (Note: the series are stubbed out with dummy data for now, but hopefully you get the idea) to a JavaScript function that returns JSON. I am having trouble finding an example of how to do this with the Telerik ASP.Net MVC Chart. I do find examples with the Kendo UI for jQuery chart - but I am not using that.
#(Html.Kendo().Chart()
.Name("GallonsPerMonth")
.Title("Total Gallons Per Month")
.Legend(legend => legend
.Position(ChartLegendPosition.Top)
.Visible(true)
)
.Theme("Bootstrap")
.ChartArea(chartArea => chartArea
.Background("transparent")
.Height(600)
)
.Series(series =>
{
series.Column(new double[] { 825, 775, 875, 900, 925, 1111, 1200, 1175, 1100, 1000, 875, 800 }).Name("Estimated");
series.Line(new double[] { 700, 795, 900, 850, 950, 905, 1175, 1100, 1000, 1050, 700, 650 }).Name("Actual").Color("red");
})
.CategoryAxis(axis => axis
.Name("series-axis")
.Line(line => line.Visible(false))
)
.CategoryAxis(axis => axis
.Name("label-axis")
.Categories("Jan", "Feb", "Mar", "Apr", "May", "Jun", "July", "Aug", "Sep", "Oct", "Nov", "Dec")
)
.ValueAxis(axis => axis//.Logarithmic()
.Numeric()
.Labels(labels => labels.Format("{0}"))
// Move the label-axis all the way down the value axis
.AxisCrossingValue(0, int.MinValue)
)
.Tooltip(tooltip => tooltip
.Visible(true)
.Format("{0}")
.Template("#= series.name #: #= value #")
)
)
dsd
You could create the chart using the MVC helper extension without the series data, so add that using JavaScript when the document is ready.
<script>
$(document).ready(function () {
$.getJSON('your-url', function (data) {
var chart = $("#GallonsPerMonth").data("kendoChart");
var series = chart.options.series;
// first series
series[0].data = data;
chart.redraw();
});
}
</script>
Note I am adding the data to the Fist Series.

Node js and mysql date [duplicate]

How do I format a Date object to a string?
If you need slightly less control over formatting than the currently accepted answer, Date#toLocaleDateString can be used to create standard locale-specific renderings. The locale and options arguments let applications specify the language whose formatting conventions should be used, and allow some customization of the rendering.
Options key examples:
day:
The representation of the day.
Possible values are "numeric", "2-digit".
weekday:
The representation of the weekday.
Possible values are "narrow", "short", "long".
year:
The representation of the year.
Possible values are "numeric", "2-digit".
month:
The representation of the month.
Possible values are "numeric", "2-digit", "narrow", "short", "long".
hour:
The representation of the hour.
Possible values are "numeric", "2-digit".
minute:
The representation of the minute.
Possible values are "numeric", "2-digit".
second:
The representation of the second.
Possible values are "numeric", 2-digit".
All these keys are optional. You can change the number of options values based on your requirements, and this will also reflect the presence of each date time term.
Note: If you would only like to configure the content options, but still use the current locale, passing null for the first parameter will cause an error. Use undefined instead.
For different languages:
"en-US": For American English
"en-GB": For British English
"hi-IN": For Hindi
"ja-JP": For Japanese
You can use more language options.
For example
var options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
var today = new Date();
console.log(today.toLocaleDateString("en-US")); // 9/17/2016
console.log(today.toLocaleDateString("en-US", options)); // Saturday, September 17, 2016
console.log(today.toLocaleDateString("hi-IN", options)); // शनिवार, 17 सितंबर 2016
You can also use the toLocaleString() method for the same purpose. The only difference is this function provides the time when you don't pass any options.
// Example
9/17/2016, 1:21:34 PM
References:
toLocaleString()
toLocaleDateString()
For custom-delimited date formats, you have to pull out the date (or time)
components from a DateTimeFormat object (which is part of the
ECMAScript Internationalization API), and then manually create a string
with the delimiters you want.
To do this, you can use DateTimeFormat#formatToParts. You could
destructure the array, but that is not ideal, as the array output depends on the
locale:
{ // example 1
let f = new Intl.DateTimeFormat('en');
let a = f.formatToParts();
console.log(a);
}
{ // example 2
let f = new Intl.DateTimeFormat('hi');
let a = f.formatToParts();
console.log(a);
}
Better would be to map a format array to resultant strings:
function join(t, a, s) {
function format(m) {
let f = new Intl.DateTimeFormat('en', m);
return f.format(t);
}
return a.map(format).join(s);
}
let a = [{day: 'numeric'}, {month: 'short'}, {year: 'numeric'}];
let s = join(new Date, a, '-');
console.log(s);
You can also pull out the parts of a DateTimeFormat one-by-one using
DateTimeFormat#format, but note that when using this method, as of March
2020, there is a bug in the ECMAScript implementation when it comes to
leading zeros on minutes and seconds (this bug is circumvented by the approach
above).
let d = new Date(2010, 7, 5);
let ye = new Intl.DateTimeFormat('en', { year: 'numeric' }).format(d);
let mo = new Intl.DateTimeFormat('en', { month: 'short' }).format(d);
let da = new Intl.DateTimeFormat('en', { day: '2-digit' }).format(d);
console.log(`${da}-${mo}-${ye}`);
When working with dates and times, it is usually worth using a library (eg. luxon, date-fns, moment.js is not recommended for new projects) because of the many hidden complexities of the field.
Note that the ECMAScript Internationalization API, used in the solutions above
is not supported in IE10 (0.03% global browser market share in Feb
2020).
If you need to quickly format your date using plain JavaScript, use getDate, getMonth + 1, getFullYear, getHours and getMinutes:
var d = new Date();
var datestring = d.getDate() + "-" + (d.getMonth()+1) + "-" + d.getFullYear() + " " +
d.getHours() + ":" + d.getMinutes();
// 16-5-2015 9:50
Or, if you need it to be padded with zeros:
var datestring = ("0" + d.getDate()).slice(-2) + "-" + ("0"+(d.getMonth()+1)).slice(-2) + "-" +
d.getFullYear() + " " + ("0" + d.getHours()).slice(-2) + ":" + ("0" + d.getMinutes()).slice(-2);
// 16-05-2015 09:50
Use the date.format library:
var dateFormat = require('dateformat');
var now = new Date();
dateFormat(now, "dddd, mmmm dS, yyyy, h:MM:ss TT");
returns:
Saturday, June 9th, 2007, 5:46:21 PM
dateformat on npm
http://jsfiddle.net/phZr7/1/
Well, what I wanted was to convert today's date to a MySQL friendly date string like 2012-06-23, and to use that string as a parameter in one of my queries. The simple solution I've found is this:
var today = new Date().toISOString().slice(0, 10);
Keep in mind that the above solution does not take into account your timezone offset.
You might consider using this function instead:
function toJSONLocal (date) {
var local = new Date(date);
local.setMinutes(date.getMinutes() - date.getTimezoneOffset());
return local.toJSON().slice(0, 10);
}
This will give you the correct date in case you are executing this code around the start/end of the day.
var date = new Date();
function toLocal(date) {
var local = new Date(date);
local.setMinutes(date.getMinutes() - date.getTimezoneOffset());
return local.toJSON();
}
function toJSONLocal(date) {
var local = new Date(date);
local.setMinutes(date.getMinutes() - date.getTimezoneOffset());
return local.toJSON().slice(0, 10);
}
// check out your devtools console
console.log(date.toJSON());
console.log(date.toISOString());
console.log(toLocal(date));
console.log(toJSONLocal(date));
Date.toISOString
Date.toJSON
String.slice
External example
Custom formatting function:
For fixed formats, a simple function make the job. The following example generates the international format YYYY-MM-DD:
function dateToYMD(date) {
var d = date.getDate();
var m = date.getMonth() + 1; //Month from 0 to 11
var y = date.getFullYear();
return '' + y + '-' + (m<=9 ? '0' + m : m) + '-' + (d <= 9 ? '0' + d : d);
}
console.log(dateToYMD(new Date(2017,10,5))); // Nov 5
The OP format may be generated like:
function dateToYMD(date) {
var strArray=['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
var d = date.getDate();
var m = strArray[date.getMonth()];
var y = date.getFullYear();
return '' + (d <= 9 ? '0' + d : d) + '-' + m + '-' + y;
}
console.log(dateToYMD(new Date(2017,10,5))); // Nov 5
Note: It is, however, usually not a good idea to extend the JavaScript standard libraries (e.g. by adding this function to the prototype of Date).
A more advanced function could generate configurable output based on a format parameter.
If to write a formatting function is too long, there are plenty of libraries around which does it. Some other answers already enumerate them. But increasing dependencies also has it counter-part.
Standard ECMAScript formatting functions:
Since more recent versions of ECMAScript, the Date class has some specific formatting functions:
toDateString: Implementation dependent, show only the date.
https://262.ecma-international.org/#sec-date.prototype.todatestring
new Date().toDateString(); // e.g. "Fri Nov 11 2016"
toISOString: Show ISO 8601 date and time.
https://262.ecma-international.org/#sec-date.prototype.toisostring
new Date().toISOString(); // e.g. "2016-11-21T08:00:00.000Z"
toJSON: Stringifier for JSON.
https://262.ecma-international.org/#sec-date.prototype.tojson
new Date().toJSON(); // e.g. "2016-11-21T08:00:00.000Z"
toLocaleDateString: Implementation dependent, a date in locale format.
https://262.ecma-international.org/#sec-date.prototype.tolocaledatestring
new Date().toLocaleDateString(); // e.g. "21/11/2016"
toLocaleString: Implementation dependent, a date&time in locale format.
https://262.ecma-international.org/#sec-date.prototype.tolocalestring
new Date().toLocaleString(); // e.g. "21/11/2016, 08:00:00 AM"
toLocaleTimeString: Implementation dependent, a time in locale format.
https://262.ecma-international.org/#sec-date.prototype.tolocaletimestring
new Date().toLocaleTimeString(); // e.g. "08:00:00 AM"
toString: Generic toString for Date.
https://262.ecma-international.org/#sec-date.prototype.tostring
new Date().toString(); // e.g. "Fri Nov 21 2016 08:00:00 GMT+0100 (W. Europe Standard Time)"
Note: it is possible to generate custom output out of those formatting >
new Date().toISOString().slice(0,10); //return YYYY-MM-DD
Examples snippets:
console.log("1) "+ new Date().toDateString());
console.log("2) "+ new Date().toISOString());
console.log("3) "+ new Date().toJSON());
console.log("4) "+ new Date().toLocaleDateString());
console.log("5) "+ new Date().toLocaleString());
console.log("6) "+ new Date().toLocaleTimeString());
console.log("7) "+ new Date().toString());
console.log("8) "+ new Date().toISOString().slice(0,10));
Specifying the locale for standard functions:
Some of the standard functions listed above are dependent on the locale:
toLocaleDateString()
toLocaleTimeString()
toLocalString()
This is because different cultures make uses of different formats, and express their date or time in different ways.
The function by default will return the format configured on the device it runs, but this can be specified by setting the arguments (ECMA-402).
toLocaleDateString([locales[, options]])
toLocaleTimeString([locales[, options]])
toLocaleString([locales[, options]])
//e.g. toLocaleDateString('ko-KR');
The option second parameter, allow for configuring more specific format inside the selected locale. For instance, the month can be show as full-text or abreviation.
toLocaleString('en-GB', { month: 'short' })
toLocaleString('en-GB', { month: 'long' })
Examples snippets:
console.log("1) "+ new Date().toLocaleString('en-US'));
console.log("2) "+ new Date().toLocaleString('ko-KR'));
console.log("3) "+ new Date().toLocaleString('de-CH'));
console.log("4) "+ new Date().toLocaleString('en-GB', { hour12: false }));
console.log("5) "+ new Date().toLocaleString('en-GB', { hour12: true }));
Some good practices regarding locales:
Most people don't like their dates to appear in a foreigner format, consequently, keep the default locale whenever possible (over setting 'en-US' everywhere).
Implementing conversion from/to UTC can be challenging (considering DST, time-zone not multiple of 1 hour, etc.). Use a well-tested library when possible.
Don't assume the locale correlate to a country: several countries have many of them (Canada, India, etc.)
Avoid detecting the locale through non-standard ways. Here you can read about the multiple pitfalls: detecting the keyboard layout, detecting the locale by the geographic location, etc..
If you are already using jQuery UI in your project you could do it this way:
var formatted = $.datepicker.formatDate("M d, yy", new Date("2014-07-08T09:02:21.377"));
// formatted will be 'Jul 8, 2014'
Some datepicker date format options to play with are available here.
Note (2022-10): toLocaleFormat has been deprecated for some time and was removed from Firefox as of version 58. See toLocaleFormat
I think you can just use the non-standard Date method toLocaleFormat(formatString)
formatString: A format string in the same format expected by the strftime() function in C.
var today = new Date();
today.toLocaleFormat('%d-%b-%Y'); // 30-Dec-2011
References:
toLocaleFormat
strftime
Plain JavaScript is the best pick for small onetimers.
On the other hand, if you need more date stuff, MomentJS is a great solution.
For example:
moment().format('YYYY-MM-DD HH:m:s'); // now() -> 2015-03-24 14:32:20
moment("20111031", "YYYYMMDD").fromNow(); // 3 years ago
moment("20120620", "YYYYMMDD").fromNow(); // 3 years ago
moment().startOf('day').fromNow(); // 11 hours ago
moment().endOf('day').fromNow(); // in 13 hours
In modern browsers (*), you can just do this:
var today = new Date().toLocaleDateString('en-GB', {
day : 'numeric',
month : 'short',
year : 'numeric'
}).split(' ').join('-');
Output if executed today (january 24ᵗʰ, 2016):
'24-Jan-2016'
(*) According to MDN, "modern browsers" means Chrome 24+, Firefox 29+, Internet Explorer 11, Edge 12+, Opera 15+ & Safari nightly build.
Requested format in one line - no libraries and no Date methods, just regex:
var d = (new Date()).toString().replace(/\S+\s(\S+)\s(\d+)\s(\d+)\s.*/,'$2-$1-$3');
// date will be formatted as "14-Oct-2015" (pass any date object in place of 'new Date()')
In my testing, this works reliably in the major browsers (Chrome, Safari, Firefox and IE.) As #RobG pointed out, the output of Date.prototype.toString() is implementation-dependent, so for international or non-browser implementations, just test the output to be sure it works right in your JavaScript engine. You can even add some code to test the string output and make sure it's matching what you expect before you do the regex replace.
Packaged Solution: Luxon or date-fns
If you want to use a one solution to fit all, I recommend using date-fns or Luxon.
Luxon is hosted on the Moment.js website and developed by a Moment.js developer because Moment.js has limitations that the developer wanted to address but couldn't.
To install:
npm install luxon or yarn add luxon (visit link for other installation methods)
Example:
luxon.DateTime.fromISO('2010-08-10').toFormat('yyyy-LLL-dd');
Yields:
10-Aug-2010
Manual Solution
Using similar formatting as Moment.js, Class DateTimeFormatter (Java), and Class SimpleDateFormat (Java), I implemented a comprehensive solution formatDate(date, patternStr) where the code is easy to read and modify. You can display date, time, AM/PM, etc. See code for more examples.
Example:
formatDate(new Date(), 'EEEE, MMMM d, yyyy HH:mm:ss:S')
(formatDate is implemented in the code snippet below)
Yields:
Friday, October 12, 2018 18:11:23:445
Try the code out by clicking "Run code snippet."
Date and Time Patterns
yy = 2-digit year; yyyy = full year
M = digit month; MM = 2-digit month; MMM = short month name; MMMM = full month name
EEEE = full weekday name; EEE = short weekday name
d = digit day; dd = 2-digit day
h = hours am/pm; hh = 2-digit hours am/pm; H = hours; HH = 2-digit hours
m = minutes; mm = 2-digit minutes; aaa = AM/PM
s = seconds; ss = 2-digit seconds
S = miliseconds
var monthNames = [
"January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"
];
var dayOfWeekNames = [
"Sunday", "Monday", "Tuesday",
"Wednesday", "Thursday", "Friday", "Saturday"
];
function formatDate(date, patternStr){
if (!patternStr) {
patternStr = 'M/d/yyyy';
}
var day = date.getDate(),
month = date.getMonth(),
year = date.getFullYear(),
hour = date.getHours(),
minute = date.getMinutes(),
second = date.getSeconds(),
miliseconds = date.getMilliseconds(),
h = hour % 12,
hh = twoDigitPad(h),
HH = twoDigitPad(hour),
mm = twoDigitPad(minute),
ss = twoDigitPad(second),
aaa = hour < 12 ? 'AM' : 'PM',
EEEE = dayOfWeekNames[date.getDay()],
EEE = EEEE.substr(0, 3),
dd = twoDigitPad(day),
M = month + 1,
MM = twoDigitPad(M),
MMMM = monthNames[month],
MMM = MMMM.substr(0, 3),
yyyy = year + "",
yy = yyyy.substr(2, 2)
;
// checks to see if month name will be used
patternStr = patternStr
.replace('hh', hh).replace('h', h)
.replace('HH', HH).replace('H', hour)
.replace('mm', mm).replace('m', minute)
.replace('ss', ss).replace('s', second)
.replace('S', miliseconds)
.replace('dd', dd).replace('d', day)
.replace('EEEE', EEEE).replace('EEE', EEE)
.replace('yyyy', yyyy)
.replace('yy', yy)
.replace('aaa', aaa);
if (patternStr.indexOf('MMM') > -1) {
patternStr = patternStr
.replace('MMMM', MMMM)
.replace('MMM', MMM);
}
else {
patternStr = patternStr
.replace('MM', MM)
.replace('M', M);
}
return patternStr;
}
function twoDigitPad(num) {
return num < 10 ? "0" + num : num;
}
console.log(formatDate(new Date()));
console.log(formatDate(new Date(), 'dd-MMM-yyyy')); //OP's request
console.log(formatDate(new Date(), 'EEEE, MMMM d, yyyy HH:mm:ss.S aaa'));
console.log(formatDate(new Date(), 'EEE, MMM d, yyyy HH:mm'));
console.log(formatDate(new Date(), 'yyyy-MM-dd HH:mm:ss.S'));
console.log(formatDate(new Date(), 'M/dd/yyyy h:mmaaa'));
Thank you #Gerry for bringing up Luxon.
#Sébastien -- alternative all browser support
new Date(parseInt(496407600)*1000).toLocaleDateString('de-DE', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
}).replace(/\./g, '/');
Documentation:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleDateString
High-order tagged template literal example based on Date.toLocaleDateString:
const date = new Date(Date.UTC(2020, 4, 2, 3, 23, 16, 738));
const fmt = (dt, lc = "en-US") => (str, ...expr) =>
str.map((str, i) => str + (expr[i]?dt.toLocaleDateString(lc, expr[i]) :'')).join('')
console.log(fmt(date)`${{year: 'numeric'}}-${{month: '2-digit'}}-${{day: '2-digit'}}`);
// expected output: "2020-05-02"
OK, we have got something called Intl which is very useful for formatting a date in JavaScript these days:
Your date as below:
var date = '10/8/2010';
And you change to Date by using new Date() like below:
date = new Date(date);
And now you can format it any way you like using a list of locales like below:
date = new Intl.DateTimeFormat('en-AU').format(date); // Australian date format: "8/10/2010"
date = new Intl.DateTimeFormat('en-US').format(date); // USA date format: "10/8/2010"
date = new Intl.DateTimeFormat('ar-EG').format(date); // Arabic date format: "٨‏/١٠‏/٢٠١٠"
If you exactly want the format you mentioned above, you can do:
date = new Date(Date.UTC(2010, 7, 10, 0, 0, 0));
var options = {year: "numeric", month: "short", day: "numeric"};
date = new Intl.DateTimeFormat("en-AU", options).format(date).replace(/\s/g, '-');
And the result is going to be:
"10-Aug-2010"
For more see the Intl API and Intl.DateTimeFormat documentation.
Using an ECMAScript Edition 6 (ES6/ES2015) string template:
let d = new Date();
let formatted = `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`;
If you need to change the delimiters:
const delimiter = '/';
let formatted = [d.getFullYear(), d.getMonth() + 1, d.getDate()].join(delimiter);
The Date constructor (and Date.parse()) only accepts one format as a parameter when constructing a date and that is ISO 8601:
// new Date('YYYY-MM-DDTHH:mm:ss.sssZ')
const date = new Date('2017-08-15')
But parsing a from a string is strongly discouraged (MDN recommends against creating date with date strings) due to browser differences and inconsistencies.
The recommended alternative would be building your Date instance directly from the numeric data like this:
new Date(2017, 7, 15) // Month is zero-indexed
That is parsing. Now, to format your date to the string you desire you have several options that are native of the Date object (although I believe none is compliant to the format you require):
date.toString() // 'Wed Jan 23 2019 17:23:42 GMT+0800 (Singapore Standard Time)'
date.toDateString() // 'Wed Jan 23 2019'
date.toLocaleString() // '23/01/2019, 17:23:42'
date.toGMTString() // 'Wed, 23 Jan 2019 09:23:42 GMT'
date.toUTCString() // 'Wed, 23 Jan 2019 09:23:42 GMT'
date.toISOString() // '2019-01-23T09:23:42.079Z'
For other formatting options I'm afraid you'll have to turn to libraries such as Moment.js, day.js and the like.
Credit to Zell Liew from this article for the date formatting tips.
Here's is some code I just wrote to handle the date formatting for a project I'm working on. It mimics the PHP date formatting functionality to suit my needs. Feel free to use it, it's just extending the already existing Date() object. This may not be the most elegant solution but it's working for my needs.
var d = new Date();
d_string = d.format("m/d/Y h:i:s");
/**************************************
* Date class extension
*
*/
// Provide month names
Date.prototype.getMonthName = function(){
var month_names = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];
return month_names[this.getMonth()];
}
// Provide month abbreviation
Date.prototype.getMonthAbbr = function(){
var month_abbrs = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec'
];
return month_abbrs[this.getMonth()];
}
// Provide full day of week name
Date.prototype.getDayFull = function(){
var days_full = [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday'
];
return days_full[this.getDay()];
};
// Provide full day of week name
Date.prototype.getDayAbbr = function(){
var days_abbr = [
'Sun',
'Mon',
'Tue',
'Wed',
'Thur',
'Fri',
'Sat'
];
return days_abbr[this.getDay()];
};
// Provide the day of year 1-365
Date.prototype.getDayOfYear = function() {
var onejan = new Date(this.getFullYear(),0,1);
return Math.ceil((this - onejan) / 86400000);
};
// Provide the day suffix (st,nd,rd,th)
Date.prototype.getDaySuffix = function() {
var d = this.getDate();
var sfx = ["th","st","nd","rd"];
var val = d%100;
return (sfx[(val-20)%10] || sfx[val] || sfx[0]);
};
// Provide Week of Year
Date.prototype.getWeekOfYear = function() {
var onejan = new Date(this.getFullYear(),0,1);
return Math.ceil((((this - onejan) / 86400000) + onejan.getDay()+1)/7);
}
// Provide if it is a leap year or not
Date.prototype.isLeapYear = function(){
var yr = this.getFullYear();
if ((parseInt(yr)%4) == 0){
if (parseInt(yr)%100 == 0){
if (parseInt(yr)%400 != 0){
return false;
}
if (parseInt(yr)%400 == 0){
return true;
}
}
if (parseInt(yr)%100 != 0){
return true;
}
}
if ((parseInt(yr)%4) != 0){
return false;
}
};
// Provide Number of Days in a given month
Date.prototype.getMonthDayCount = function() {
var month_day_counts = [
31,
this.isLeapYear() ? 29 : 28,
31,
30,
31,
30,
31,
31,
30,
31,
30,
31
];
return month_day_counts[this.getMonth()];
}
// format provided date into this.format format
Date.prototype.format = function(dateFormat){
// break apart format string into array of characters
dateFormat = dateFormat.split("");
var date = this.getDate(),
month = this.getMonth(),
hours = this.getHours(),
minutes = this.getMinutes(),
seconds = this.getSeconds();
// get all date properties ( based on PHP date object functionality )
var date_props = {
d: date < 10 ? '0'+date : date,
D: this.getDayAbbr(),
j: this.getDate(),
l: this.getDayFull(),
S: this.getDaySuffix(),
w: this.getDay(),
z: this.getDayOfYear(),
W: this.getWeekOfYear(),
F: this.getMonthName(),
m: month < 10 ? '0'+(month+1) : month+1,
M: this.getMonthAbbr(),
n: month+1,
t: this.getMonthDayCount(),
L: this.isLeapYear() ? '1' : '0',
Y: this.getFullYear(),
y: this.getFullYear()+''.substring(2,4),
a: hours > 12 ? 'pm' : 'am',
A: hours > 12 ? 'PM' : 'AM',
g: hours % 12 > 0 ? hours % 12 : 12,
G: hours > 0 ? hours : "12",
h: hours % 12 > 0 ? hours % 12 : 12,
H: hours,
i: minutes < 10 ? '0' + minutes : minutes,
s: seconds < 10 ? '0' + seconds : seconds
};
// loop through format array of characters and add matching data else add the format character (:,/, etc.)
var date_string = "";
for(var i=0;i<dateFormat.length;i++){
var f = dateFormat[i];
if(f.match(/[a-zA-Z]/g)){
date_string += date_props[f] ? date_props[f] : '';
} else {
date_string += f;
}
}
return date_string;
};
/*
*
* END - Date class extension
*
************************************/
This may help with the problem:
var d = new Date();
var options = {
day: 'numeric',
month: 'long',
year: 'numeric'
};
console.log(d.toLocaleDateString('en-ZA', options));
A useful and flexible way for formatting the DateTimes in JavaScript is Intl.DateTimeFormat:
var date = new Date();
var options = { year: 'numeric', month: 'short', day: '2-digit'};
var _resultDate = new Intl.DateTimeFormat('en-GB', options).format(date);
// The _resultDate is: "12 Oct 2017"
// Replace all spaces with - and then log it.
console.log(_resultDate.replace(/ /g,'-'));
Result Is: "12-Oct-2017"
The date and time formats can be customized using the options argument.
The Intl.DateTimeFormat object is a constructor for objects that enable language sensitive date and time formatting.
Syntax
new Intl.DateTimeFormat([locales[, options]])
Intl.DateTimeFormat.call(this[, locales[, options]])
Parameters
locales
Optional. A string with a BCP 47 language tag, or an array of such strings. For the general form and interpretation of the locales argument, see the Intl page. The following Unicode extension keys are allowed:
nu
Numbering system. Possible values include: "arab", "arabext", "bali", "beng", "deva", "fullwide", "gujr", "guru", "hanidec", "khmr", "knda", "laoo", "latn", "limb", "mlym", "mong", "mymr", "orya", "tamldec", "telu", "thai", "tibt".
ca
Calendar. Possible values include: "buddhist", "chinese", "coptic", "ethioaa", "ethiopic", "gregory", "hebrew", "indian", "islamic", "islamicc", "iso8601", "japanese", "persian", "roc".
Options
Optional. An object with some or all of the following properties:
localeMatcher
The locale matching algorithm to use. Possible values are "lookup" and "best fit"; the default is "best fit". For information about this option, see the Intl page.
timeZone
The time zone to use. The only value implementations must recognize is "UTC"; the default is the runtime's default time zone. Implementations may also recognize the time zone names of the IANA time zone database, such as "Asia/Shanghai", "Asia/Kolkata", "America/New_York".
hour12
Whether to use 12-hour time (as opposed to 24-hour time). Possible values are true and false; the default is locale dependent.
formatMatcher
The format matching algorithm to use. Possible values are "basic" and "best fit"; the default is "best fit". See the following paragraphs for information about the use of this property.
The following properties describe the date-time components to use in formatted output and their desired representations. Implementations are required to support at least the following subsets:
weekday, year, month, day, hour, minute, second
weekday, year, month, day
year, month, day
year, month
month, day
hour, minute, second
hour, minute
Implementations may support other subsets, and requests will be negotiated against all available subset-representation combinations to find the best match. Two algorithms are available for this negotiation and selected by the formatMatcher property: A fully specified "basic" algorithm and an implementation dependent "best fit" algorithm.
weekday
The representation of the weekday. Possible values are "narrow", "short", "long".
era
The representation of the era. Possible values are "narrow", "short", "long".
year
The representation of the year. Possible values are "numeric", "2-digit".
month
The representation of the month. Possible values are "numeric", "2-digit", "narrow", "short", "long".
day
The representation of the day. Possible values are "numeric", "2-digit".
hour
The representation of the hour. Possible values are "numeric", "2-digit".
minute
The representation of the minute. Possible values are "numeric", "2-digit".
second
The representation of the second. Possible values are "numeric", "2-digit".
timeZoneName
The representation of the time zone name. Possible values are "short", "long".
The default value for each date-time component property is undefined, but if all component properties are undefined, then the year, month and day are assumed to be "numeric".
Check Online
More Details
A JavaScript solution without using any external libraries:
var now = new Date()
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
var formattedDate = now.getDate() + "-" + months[now.getMonth()] + "-" + now.getFullYear()
alert(formattedDate)
new Date().toLocaleDateString()
// "3/21/2018"
More documentation at developer.mozilla.org
We have lots of solutions for this, but I think the best of them is Moment.js. So I personally suggest to use Moment.js for date and time operations.
console.log(moment().format('DD-MMM-YYYY'));
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.14.1/moment.min.js"></script>
If you are using jQuery UI in your code, there is an inbuilt function called formatDate(). I am using it this way to format today's date:
var testdate = Date();
testdate = $.datepicker.formatDate( "d-M-yy",new Date(testdate));
alert(testdate);
You can see many other examples of formatting date in the jQuery UI documentation.
This is how I implemented for my npm plugins
var monthNames = [
"January", "February", "March",
"April", "May", "June", "July",
"August", "September", "October",
"November", "December"
];
var Days = [
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"
];
var formatDate = function(dt,format){
format = format.replace('ss', pad(dt.getSeconds(),2));
format = format.replace('s', dt.getSeconds());
format = format.replace('dd', pad(dt.getDate(),2));
format = format.replace('d', dt.getDate());
format = format.replace('mm', pad(dt.getMinutes(),2));
format = format.replace('m', dt.getMinutes());
format = format.replace('MMMM', monthNames[dt.getMonth()]);
format = format.replace('MMM', monthNames[dt.getMonth()].substring(0,3));
format = format.replace('MM', pad(dt.getMonth()+1,2));
format = format.replace(/M(?![ao])/, dt.getMonth()+1);
format = format.replace('DD', Days[dt.getDay()]);
format = format.replace(/D(?!e)/, Days[dt.getDay()].substring(0,3));
format = format.replace('yyyy', dt.getFullYear());
format = format.replace('YYYY', dt.getFullYear());
format = format.replace('yy', (dt.getFullYear()+"").substring(2));
format = format.replace('YY', (dt.getFullYear()+"").substring(2));
format = format.replace('HH', pad(dt.getHours(),2));
format = format.replace('H', dt.getHours());
return format;
}
pad = function(n, width, z) {
z = z || '0';
n = n + '';
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
}
You should have a look at DayJs It's a remake of momentJs but modular architecture oriented so lighter.
Fast 2kB alternative to Moment.js with the same modern API
Day.js is a minimalist JavaScript library that parses, validates, manipulates, and displays dates and times for modern browsers with a largely Moment.js-compatible API. If you use Moment.js, you already know how to use Day.js.
var date = Date.now();
const formatedDate = dayjs(date).format("YYYY-MM-DD")
console.log(formatedDate);
<script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.8.16/dayjs.min.js" crossorigin="anonymous"></script>
var today = new Date();
var formattedToday = today.toLocaleDateString() + ' ' + today.toLocaleTimeString();
Inspired by JD Smith's marvellous regular expression solution, I suddenly had this head-splitting idea:
var D = Date().toString().split(" ");
console.log(D[2] + "-" + D[1] + "-" + D[3]);
For any one looking for a really simple ES6 solution to copy, paste and adopt:
const dateToString = d => `${d.getFullYear()}-${('00' + (d.getMonth() + 1)).slice(-2)}-${('00' + d.getDate()).slice(-2)}`
// how to use:
const myDate = new Date(Date.parse('04 Dec 1995 00:12:00 GMT'))
console.log(dateToString(myDate)) // 1995-12-04
As of 2019, it looks like you can get toLocaleDateString to return only certain parts and then you can join them as you wish:
var date = new Date();
console.log(date.toLocaleDateString("en-US", { day: 'numeric' })
+ "-"+ date.toLocaleDateString("en-US", { month: 'short' })
+ "-" + date.toLocaleDateString("en-US", { year: 'numeric' }) );
> 16-Nov-2019
console.log(date.toLocaleDateString("en-US", { month: 'long' })
+ " " + date.toLocaleDateString("en-US", { day: 'numeric' })
+ ", " + date.toLocaleDateString("en-US", { year: 'numeric' }) );
> November 16, 2019
It works same in Internet Explorer 11, Firefox, and Chrome (Chrome 80.x shows 12 hours format when en-UK selected).
const d = new Date('2010/08/05 23:45') // 26.3.2020
const dtfUK = new Intl.DateTimeFormat('UK', { year: 'numeric', month: '2-digit', day: '2-digit',
hour: '2-digit',minute: '2-digit', second: '2-digit' }); //
const dtfUS = new Intl.DateTimeFormat('en', { year: 'numeric', month: '2-digit', day: '2-digit',
hour: '2-digit',minute: '2-digit', second: '2-digit' }); //
console.log(dtfUS.format(d)); // 08/05/2010 11:45:00 PM
console.log(dtfUK.format(d)); // 05.08.2010 23:45:00
/* node.js:
08/05/2010, 11:45:00 PM
2010-08-05 23:45:00
*/
What about something more general?
var d = new Date('2010-08-10T10:34:56.789Z');
var str = d.toDateString() + // Tue Aug 10 2010
' ' + d.toTimeString().split(' ')[0] + // 12:34:56, GMT+0x00 (GMT+0x:00)
' ' + (d.getMonth() + 101) + // 108
' ' + d.getMilliseconds(); // 789
console.log(str); // Tue Aug 10 2010 12:34:56 108 789
console.log(// $1 Tue $2 Aug $3 11 $4 2020 $5 12 $6 34 $7 56 $8 108 $9 789
str.replace(/(\S{3}) (\S{3}) (\d{1,2}) (\d{4}) (\d{2}):(\d{2}):(\d{2}) 1(\d{2}) (\d{1,3})/, '$3-$2-$4 $5:$6.$9 ($1)')
); // 10-Aug-2010 12:34.789 (Tue)
/*
$1: Tue Week Day string
$2: Aug Month short text
$3: 11 Day
$4: 2010 Year
$5: 12 Hour
$6: 34 Minute
$7: 56 Seconds
$8: 08 Month
$9: 789 Milliseconds
*/
Or for example 1-line IIFE "library" ;-)
console.log(
(function (frm, d) { return [d.toDateString(), d.toTimeString().split(' ')[0], (d.getMonth() + 101), d.getMilliseconds()].join(' ').replace(/(\S{3}) (\S{3}) (\d{1,2}) (\d{4}) (\d{2}):(\d{2}):(\d{2}) 1(\d{2}) (\d{1,3})/, frm); })
('$4/$8/$3 $5:$6 ($1)', new Date())
);
You can remove useless parts and / or change indexes if you do not need them.

HTML - dynamic url a href

I'm completely new to the world of HTML.
I have an HTML file that contains a link similar to below:
<tr><a href=Report_201508_11Aug15.pdf>Report_11Aug15</a></tr>
the '201508_11Aug15' represents the date of the report.
Instead of hardcoding the date for each report, I would instead like to use a date function to locate the report and display a link for it.
so it would become
<tr><a href=Report_(Today's date in format above).pdf>Report_(Today's date in format above)</a></tr>
Please advise on how to achieve this? I would then want to go to older dates (e.g. Today's date - 1, -2, - 3 etc).
Thanks in advance.
if your are looking for client side solution you can do this using Javascript.
var monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
var d = new Date();
var month = d.getMonth() + 1;
var name='Report_';
name+=d.getFullYear();
name+=month.toString().length==1?('0'+month):month;
name+='_';
name+=d.getDate()+1;
name+=monthNames[month];
name+=d.getFullYear().toString().substr(2);
name+='.pdf';
Fiddle: DEMO

Flex columnset not displayed properly

I am developing a chart in which i need to have multiple column sets but flex is giving me strange results for it. I am using parsley framework.
Here is my mxml code
<mx:ColumnChart id="columnChart"
width="100%" height="100%"
dataProvider="{myPM.myData}"
showDataTips="true"
click="handleChartClick(event)"
backgroundElements="{backgroundGrids}"
dataTipFunction="{myPM.formatColumnChartToolTipData}"
type="clustered"
>
<mx:horizontalAxis>
<mx:CategoryAxis id="hAxis"
categoryField="{myPM.xFieldLabel}"
title="{myPM.xAxisDisplayLabel}"/>
</mx:horizontalAxis>
<mx:verticalAxis>
<mx:LinearAxis id="vAxis"
title="{myPM.yAxisDisplayLabel}"/>
</mx:verticalAxis>
<mx:series>
**works perfecly fine if i change type="clustered"**
<mx:ColumnSet series="{myPM.columnSeries}"
type="stacked"
verticalAxis="{vAxis}"
>
</mx:ColumnSet>
<mx:ColumnSet>
<mx:ColumnSeries xField="{myPM.xFieldLabel}"
yField="{myPM.yFieldLabel}"
displayName="year"/>
</mx:ColumnSet>
</mx:series>
</mx:ColumnChart>
In my presentation model i am returning column series which is presented in the following code
public class MyPM
{
public var columnSeries:Array;
public void init()
{
columnSeries=getColumnSeries();
}
public function getColumnSeries():Array
{
var series:Array = new Array();
var columnSeries:ColumnSeries;
columnSeries=new ColumnSeries();
//columnSeries.xField=xFieldLabel;
columnSeries.yField="quarter1_profit_count";
columnSeries.displayName="quarter1_title";
series.push(columnSeries);
columnSeries=new ColumnSeries();
//columnSeries.xField=xFieldLabel;
columnSeries.yField="quarter2_profit_count";
columnSeries.displayName="quarter2_title";
series.push(columnSeries);
columnSeries=new ColumnSeries();
//columnSeries.xField=xFieldLabel;
columnSeries.yField="quarter3_profit_count";
columnSeries.displayName="quarter3_title";
series.push(columnSeries);
columnSeries=new ColumnSeries();
//columnSeries.xField=xFieldLabel;
columnSeries.yField="quarter4_profit_count";
columnSeries.displayName="quarter4_title";
series.push(columnSeries);
return series;
}
}
The problem i am getting here is
"In first column there should be 4 stacked column series but flex drops 1 out of 4 stacked column series ( i am able to see only 3 or 2 columns it drops remaining one). I have debugged my code and the data is coming perfectly fine. If i remove all the column sets and write like then it gives me correct result for the first stacked column. But as i want the second column also which will have summation of all data at one place. for e.g. 1st stacked column will be showing quarterwise profit amounts and the second column i want to have to display total profit throughout the year."
You can see the charts here
- without using columnsets and binding series directly in definition
- as you can see the quarters are dropped here. in both the charts data source is same
I am not knowing what i am doing wrong here. Any kind of help will be
appreciated. Thanks in advance.
After a lot of effort i come to the solution. Here is the code for that.
public function getColumnSeries():Array
{
var series:Array = new Array();
var set1:ColumnSet =new ColumnSet();
set1.type="stacked";
var set2:ColumnSet=new ColumnSet();
set2.type="stacked";
var columnSeries:ColumnSeries;
columnSeries=new ColumnSeries();
//columnSeries.xField=xFieldLabel;
columnSeries.yField="quarter1_profit_count";
columnSeries.displayName="quarter1_title";
series.push(columnSeries);
columnSeries=new ColumnSeries();
//columnSeries.xField=xFieldLabel;
columnSeries.yField="quarter2_profit_count";
columnSeries.displayName="quarter2_title";
series.push(columnSeries);
columnSeries=new ColumnSeries();
//columnSeries.xField=xFieldLabel;
columnSeries.yField="quarter3_profit_count";
columnSeries.displayName="quarter3_title";
series.push(columnSeries);
columnSeries=new ColumnSeries();
//columnSeries.xField=xFieldLabel;
columnSeries.yField="quarter4_profit_count";
columnSeries.displayName="quarter4_title";
series.push(columnSeries);
set1.series=series;
//similarly for set2
series=new Array();
//add columnseries to series
set2.series=series;
var temp:Array=new Array();
temp.push(set1);
temp.push(set2);
return temp;
}
Also along with this make sure that you calculate max and min values for the y axis otherwise it will not render propery. This was also one of the reason why my chart was not getting displayed in the way i wanted.
Here is the updated markup
<mx:ColumnChart id="columnChart"
width="100%" height="100%"
dataProvider="{myPM.myData}"
showDataTips="true"
click="handleChartClick(event)"
backgroundElements="{backgroundGrids}"
dataTipFunction="{myPM.formatColumnChartToolTipData}"
type="clustered"
series={myPM.series}
>
<mx:horizontalAxis>
<mx:CategoryAxis id="hAxis"
categoryField="{myPM.xFieldLabel}"
title="{myPM.xAxisDisplayLabel}"/>
</mx:horizontalAxis>
<mx:verticalAxis>
<mx:LinearAxis id="vAxis"
title="{myPM.yAxisDisplayLabel}"/>
</mx:verticalAxis>
</mx:ColumnChart>

List with different column count

As the pic show(This is drawn by PhotoShop, not implemented yet), I want to implemnt a List like this one. It has different column count, say the first row has only one item, and the others have two items . I tried to use itemRendererFunction to detect the different item(the first row treat as a rendererA, the others treat as another rendererB),but it didn't work.
The cleanest solution to this problem, is to create a custom layout (we've discussed in the comments how Romi's solution will eventually cause too many problems). However, this is usually not an easy thing to do.
I will give you a rough sketch of what this custom layout might look like, so you can use it as a starting point to create one that does exactly what you need.
To create a custom layout, you must subclass BaseLayout and override and implement its updateDisplayList and measure methods.
To make things easier (and in order not to dump 500 lines of code in here), I used some hardcoded variables for this example. It assumes there will always be two columns, the first item will always be 200x200 px, and the other items will always be 100x100 px. There is no horizontalGap or verticalGap.
The consequence is of course that you can use this custom layout (as it is now) only for this specific List and these specific ItemRenderers. If you want it to be more generic, you'll have to do a lot more calculations.
But now for the code:
public class MyCustomLayout extends LayoutBase {
//hardcoded variables
private var columnCount:int = 2;
private var bigTileWidth:Number = 200;
private var bigTileHeight:Number = 200;
private var smallTileWidth:Number = 100;
private var smallTileHeight:Number = 100;
override public function updateDisplayList(width:Number, height:Number):void {
var layoutTarget:GroupBase = target;
if (!layoutTarget) return;
var numElements:int = layoutTarget.numElements;
if (!numElements) return;
//position and size the first element
var el:ILayoutElement = useVirtualLayout ?
layoutTarget.getVirtualElementAt(0) : layoutTarget.getElementAt(0);
el.setLayoutBoundsSize(bigTileWidth, bigTileHeight);
el.setLayoutBoundsPosition(0, 0);
//position & size the other elements in 2 columns below the 1st element
for (var i:int=1; i<numElements; i++) {
var x:Number = smallTileWidth * ((i-1) % 2);
var y:Number = smallTileHeight * Math.floor((i-1) / 2) + bigTileHeight;
el = useVirtualLayout ?
layoutTarget.getVirtualElementAt(i) :
layoutTarget.getElementAt(i);
el.setLayoutBoundsSize(smallTileWidth, smallTileHeight);
el.setLayoutBoundsPosition(x, y);
}
//set the content size (necessary for scrolling)
layoutTarget.setContentSize(
layoutTarget.measuredWidth, layoutTarget.measuredHeight
);
}
override public function measure():void {
var layoutTarget:GroupBase = target;
if (!layoutTarget) return;
var rowCount:int = Math.ceil((layoutTarget.numElements - 1) / 2);
//measure the total width and height
layoutTarget.measuredWidth = layoutTarget.measuredMinWidth =
Math.max(smallTileWidth * columnCount, bigTileWidth);
layoutTarget.measuredHeight = layoutTarget.measuredMinHeight =
bigTileHeight + smallTileHeight * rowCount;
}
}
And you can use it like this:
<s:List dataProvider="{dp}" height="300">
<s:layout>
<l:MyCustomLayout />
</s:layout>
</s:List>
Whenever you want to change the defined behavior of an existing component, always check first if you can solve the problem with skinning. It is a really powerful feature i Flex, and can also provide a solution in this case.
So, let's begin, assuming you already have your List, you only need to create a custom skin which "splits" the data provider in two parts, the first item, and all the others. So, let's assume we have this initial setup:
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var c:ArrayCollection = new ArrayCollection([
"String 1",
"String 2",
"String 3",
"String 4",
"String 5",
"String 6",
"String 7",
"String 8",
"String 9",
"String 10",
"String 11",
"String 12",
"String 13",
"String 14",
"String 15"]);
]]>
</fx:Script>
<s:List skinClass="CustomSkinList" dataProvider="{c}" />
As you can see, we define a custom list skin, which is just a copy of spark.skins.spark.ListSkin, the default skin for spark.components.List element.
Before we handle the data provider logic, we need to take a look at how the list items are rendered. This is done by using a DataGroup element, added to the skin, like so:
<s:Scroller left="0" top="0" right="0" bottom="0" id="scroller" minViewportInset="1" hasFocusableChildren="false">
<!--- #copy spark.components.SkinnableDataContainer#dataGroup -->
<s:DataGroup id="dataGroup" itemRenderer="spark.skins.spark.DefaultItemRenderer">
<s:layout>
<!--- The default layout is vertical and measures at least for 5 rows.
When switching to a different layout, HorizontalLayout for example,
make sure to adjust the minWidth, minHeight sizes of the skin -->
<s:VerticalLayout gap="0" horizontalAlign="contentJustify" requestedMinRowCount="5" />
</s:layout>
</s:DataGroup>
</s:Scroller>
Here is the place where we will have to make the changes, in order to get the first element to render differently. What we need to do, is just add another DataGroup, for rendering the first element in a custom way (this of course means using a custom item renderer). Now, our scroller looks like this:
<s:Scroller left="0"
top="0"
right="0"
bottom="0"
id="scroller"
minViewportInset="1"
hasFocusableChildren="false">
<!--- #copy spark.components.SkinnableDataContainer#dataGroup -->
<s:VGroup width="100%" height="100%">
<s:DataGroup id="firstItemDataGroup"
width="100%"
itemRenderer="CustomItemRenderer"
height="20">
<s:layout>
<s:VerticalLayout />
</s:layout>
</s:DataGroup>
<s:DataGroup id="dataGroup" itemRenderer="spark.skins.spark.DefaultItemRenderer">
<s:layout>
<!--- The default layout is vertical and measures at least for 5 rows.
When switching to a different layout, HorizontalLayout for example,
make sure to adjust the minWidth, minHeight sizes of the skin -->
<s:TileLayout horizontalAlign="center" requestedColumnCount="2" />
</s:layout>
</s:DataGroup>
</s:VGroup>
</s:Scroller>
Notice the 'firstItemDataGroup' addition, also the fact that it uses a different item renderer, than the default dataGroup element. With this new container in place we can proceed to render the elements. The custom skin need to override the parent initializationComplete() method, like so:
override protected function initializationComplete():void
{
useChromeColor = true;
if (hostComponent.dataProvider && hostComponent.dataProvider.length > 0)
{
var allItems:Array = hostComponent.dataProvider.toArray().concat();
firstItemDataGroup.dataProvider = new ArrayCollection([hostComponent.dataProvider.getItemAt(0)]);
var remainingItems:Array = allItems.concat().reverse();
remainingItems.pop();
var reversed:Array = remainingItems.reverse();
dataGroupProvider = new ArrayCollection(reversed);
}
super.initializationComplete();
}
What was added was just the 'if' block, and a private variable, named dataGroupProvider. This is because we will set the new dataProvider, the one starting from the second element, to the dataGroup element, in the updateDisplayList() method. Here is what it looks like:
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
if (getStyle("borderVisible") == true)
{
border.visible = true;
background.left = background.top = background.right = background.bottom = 1;
scroller.minViewportInset = 1;
}
else
{
border.visible = false;
background.left = background.top = background.right = background.bottom = 0;
scroller.minViewportInset = 0;
}
// Here we assign the new data provider to the dataGroup element
if (dataGroupProvider)
dataGroup.dataProvider = dataGroupProvider;
borderStroke.color = getStyle("borderColor");
borderStroke.alpha = getStyle("borderAlpha");
super.updateDisplayList(unscaledWidth, unscaledHeight);
}
In conclusion, just by creating a custom skin for our List element, we can use two containers for rendering the first item in a different way, from the rest of the elements. You shouldn't underestimate the power of Flex Skinning :)
Hope this helps. Have a great day!