Monday, February 28, 2011

Iterating the list on jQuery from the list returned by ASP.NET MVC function

Given this:

<script type="text/javascript">
    function testList() {
        $.ajax(
        {
            url: '/Music/List/',
            type: 'POST',
            dataType: 'json',
            success: function (result) {
                $.each(result.Songs, function () {
                    alert(this.Title + ', ' + this.Album + ', ' + this.YearReleased );
                });
            }
        });
    }
</script>

And this:

<input type="submit" value="Test" onclick="testList(); return false;" />

And this model:

namespace SampleJquery.Models
{
    public class Song
    {
        public string Title { get; set; }
        public string Album { get; set; }        
        public int YearReleased { get; set; } 
    }
}

This is how your ControllerHere/MethodHere shall look like:

namespace SampleJquery.Controllers
{
    public class MusicController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }


        [HttpPost]
        public JsonResult List()
        {
            return Json(
                new 
                { 
                    Songs = 
                        new Song[]
                        {
                            new Song { Title = "Taxman", Album = "Revolver", YearReleased = 1966 },
                            new Song { Title = "Girl", Album = "Rubber Soul", YearReleased = 1965 },
                            new Song { Title = "Come together", Album = "Abbey Road", YearReleased = 1969 }
                        }
                });
        }

    }
}

Notice that in jQuery's AJAX call, we don't invoke the full controller name (i.e. MusicController), we just need to invoke the function using the controller's public url slash method:

url: "/Music/List/",



If plain javascript is desired for iterating the list, you can use:

<script type="text/javascript">
    function testList() {        
        $.ajax(
        {
            url: '/Music/List/',
            type: 'POST',
            dataType: 'json',
            success: function (result) {                
                for (var i in result.Songs) {
                    var song = result.Songs[i];
                    alert(song.Title + ', ' + song.Album + ', ' + song.YearReleased);
                }
            }
        });
    }
</script>

But please do bear in mind that you will bear the wrath of jQuery peeps by doing so :D lol

Sunday, February 27, 2011

Invoking an ASP.NET MVC function from jQuery

Given this:

<script type="text/javascript">
    function test() {
        $.ajax(
        {
            url: "/Music/Save/",
            type: 'POST',
            dataType: 'json',
            data:
            {
                Title: $("#Title").val(),
                Album: $("#Album").val(),
                YearReleased: $("#YearReleased").val()
            },
            success: function (result) {
                alert(result.Something);
            }
        });
    }
</script>


And this:

<input type="submit" value="Create" onclick="test(); return false;" />

And this model:
namespace SampleJquery.Models
{
    public class Song
    {
        public string Title { get; set; }
        public string Album { get; set; }        
        public int YearReleased { get; set; } 
    }
}

This is how your ControllerHere/MethodHere shall look like:

namespace SampleJquery.Controllers
{
    public class MusicController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public JsonResult Save(Song s)
        {
            return Json(new { Something = s.Title + " " + s.Album + " " + s.YearReleased.ToString() });
        }

    }
}


Notice that in jQuery's AJAX call, we don't invoke the full controller name, we just need to invoke the function using the controller's public url slash method:

url: "/Music/Save/",

Saturday, February 19, 2011

PLDT's malpractices, ticks me off to no end

I don't do rants on blogs, but PLDT's malpractices really ticks me off and compelled me to make an exception. They still don't act on my request to revert back my internet plan to old pricing. So, I just decided to make an open letter, to make the other PLDT customers aware



Dear PLDT,


First, of all, I would like to applaud many of your salespersons who are calling my home last 2010 and being honest when they are offering 768 kbps just by adding Php 300 to the bill, they know the fine print and they would let the customers know, they would say it's 768 kbps for PLDT WatchPad only, and 512 kbps only for the rest. As I don't want marginal increase in speed, I declined their offers consistently.



All is well, until last December 2010; one of your sales person makes a false marketing, she offered 768 kbps just by adding Php 300, and I explicitly asked if it's 768 kbps for everything, not only for PLDT WatchPad, she say yes, I even asked all the basic stuff outside of PLDT WatchPad, e.g. browsing, Facebook, Skype, Youtube, etc, if it is 768 kbps, she made a resounding answer of Yes. I reiterated to her that I thought 768k kbps is for WatchPad only; she made a resounding answer that it's 768 kbps for everything, not on WatchPad only.



You have sales person(s) who are practicing false marketing.


Please restore the old pricing, Php 990. You are making your customer feel disappointed.


To cut the story short, my speed didn't even increase in speed, it stays at 360 kbps. To add insult to the injury, I called you last January, and you said the plan Php 1,299 is 512 kbps only for data, and it's 768 kbps only for PLDT watchpad. And... you didn't even deliver 512 kbps to your loyal customer.



You only increase my payment (Php 1,299), my speed is still stuck at 360 kbps. Even you increase it to 512 kbps, I would rather keep the old speed and old payment plan (Php 990), 384 kbps to 512 kbps speed increase is very marginal, not worth it. Please restore my old payment plan.



Now, the last time I call you when I said I want to go back to the old pricing, you said that I needed to pay the disconnection fee of the new pricing before I can revert back the the old pricing. You said to your customer that the disconnection fee is 1,299 X 3 months. Now what, you made a marketing deception, and you are making your customer pay dearly for it?



Many of your sales persons are not aware of plan 768 kbps fine print, I called you many times, some symphatizes with me and say it's 768 kbps for everything, not only on PLDT WatchPad, and they say they will do something; and some say it's 512 kbps only, that it's 768 kbps only if the customer is using WatchPad. And I don't intend to watch on WatchPad, heck it didn't even run on an other platforms that's gaining traction already, e.g. Mac OS X


PLDT, the big company, please align your people. Some are unwittingly making false marketing, I don't know if the last one who called me on December deliberately fooled me, but I really explicitly asked if 768 kbps is for everything, not only for PLDT Watchpad, she confirmed it.


Your disenfranchised customer,

Michael Buen

Friday, February 18, 2011

ASP.NET MVC-backed jQuery AJAX ComboBox

Look Ma! No ViewState!

I've ported a PHP-backed jQuery Ajax ComboBox to ASP.NET MVC one. You could download it at http://code.google.com/p/asp-net-mvc-backed-jquery-ajax-combobox/downloads/list


Ignore ASP.NET MVC at your own peril 1


Ignore ASP.NET MVC at your own peril 2

This is another quite debated point. At first sight, ASP.NET MVC seems to be a whole step backwards as far as productivity is concerned. What’s your definition of productivity? Being able to write 10 Web pages a day? I agree that if you take a quantity-based approach to measure productivity, ASP.NET MVC will lose the game with ASP.NET Web Forms. The “productivity” that the server control model guarantees is really hard to beat. But we are used to adding several days of maintenance and post-delivery debug to our counts for a project. This is largely due to the low quality of the code the Web Forms model allows us to write—most of the time.

Low quality is loss of money. The “apparent” speed (oops, productivity) is partly lost due to the extra work of post-delivery debug, optimization, fine-tuning, refactoring, and testing. An initial higher quality of code will take more time to get into production but will save extra work later.

Once you use it, you inevitably find out that ASP.NET MVC is highly productive—much more than Web Forms. Quick code of higher quality. It won’t happen on day 1, though, and it requires awareness and a bit of study. ASP.NET MVC propounds a quality-based approach to productivity.


"How to argue properly"

"Keep your friends close and your friends that can help you debug regexs even closer."

UPDATE: April 16, 2011

I wrote an ASP.NET Helper for jQuery Ajax ComboBox

Monday, February 14, 2011

Error on sqlite_open

If you encounter this error on IIS

PHP Fatal error: Call to undefined function sqlite_open()


Uncomment this:

extension=php_sqlite.dll

And this:

extension_dir = "ext"

Sunday, February 13, 2011

How to loop the folder's content in SSIS. In 10 easy-to-follow steps

First, drag the Data Flow Task to Foreach Loop Container:


Then press right click on Foreach Loop Container, select Edit..., select Variable Mappings; then on Select the variables to map to the collection value, click the Variable's cell, select <New Variable...>


Then on Name textbox, type this: Fullfilename:



Click OK, then select Collection(on left navigation, between General and  Variable Mappings), then click the ellipsis button [...] of Expressions, then on Property's cell, click the dropdown then select FileNameRetrieval, then click the ellipsis button [...] of Expression's cell


Then drag the [User::Filename] to Expression's text area


Then click OK two times to go back to Foreach Loop editor. If the Enumerator configuration don't appear as follows, trick Business Intelligent Development Studio, on Enumerator, select any option, then select back the Foreach File Enumerator. Then specify the source Folder of text files, you can click the Browse button to do this. On Files, enter the wildcard, it could be *.csv or *.txt, depending on the file extension that was given to text file. Then click OK



Then go to Data Flow, select the text file connection from the bottom:



Then select, the Expression property:



Then on Property Expressions Editor, select the ConnectionString from Property's cell dropdown


Then click the Expression's ellipsis button, then drag the @[User::Filename] (from the Variables list) to Expression's text area, then the Property Expressions Editor should appear as follows:


Click OK until you get back to Data Flow tab. Click the right green arrow button (shortcut key: F5)

That's it!

Happy transforming! :-)


Video how-to:

Tuesday, February 8, 2011

Dream feature, LIMIT clause on aggregate functions

select student, 
array_to_string( 
    array_agg(grade order by grade desc limit 2), ',' ) as two_best_grades
from 
student_grades
group by student;

Sunday, February 6, 2011

How to find the second best grade of a student. Using Postgresql user-defined aggregate

You can define your own aggregate function in Postgres, let's say you want to get only two array elements from a set of rows, you can use this (this violates DestroyCity principle though, but we are constrained by the fact that user-defined-aggregates accepts function with two parameters only, so there's nothing we can do about it):

create aggregate two_elements(anyelement)
(
sfunc = array_limit_two,
stype = anyarray,
initcond = '{}'
);

create or replace function array_limit_two(anyarray, anyelement) returns anyarray
as 
$$
begin
 if array_upper($1,1) = 2 then
  return $1;
 else
  return array_append($1, $2);
 end if;
end;
$$ language 'plpgsql';

Get the data here: How to find the second best grade of a student?

Then this...

select student, two_elements(grade order by grade desc)
from 
student_grades
group by student;

...will return(two best grades of a student):

student | two_elements 
---------+--------------
 george  | {40}
 john    | {100,90}
 paul    | {50,30}

To return the second best grades only, use this:

select student, array_min( two_elements(grade order by grade desc) )
from 
student_grades
group by student;

Here's the array_min function:
create or replace function array_min(anyarray) returns anyelement
as
$$
select min(unnested) from( select unnest($1) unnested ) as x
$$ language sql;

 student | array_min 
---------+-----------
 george  |        40
 john    |        90
 paul    |        30
(3 rows)


I think this code is more performant than the previous one


Wisdom of the day:

Unless you actually are going to solve the general problem, don't try and put in place a framework for solving a specific one, because you don't know what that framework should look like.

Wisdom source: http://tirania.org/blog/archive/2003/Sep-29.html

How to find the second best grade of a student?

How to find the second best grade of the student? (If there's no second grade, just return the first one)

create table student_grades
(
student varchar(100),
grade int
);

insert into student_grades values 
('john',70),
('john',80),
('john',90),
('john',100);


insert into student_grades values
('paul',20),
('paul',10),

('paul',50),
('paul',30);


insert into student_grades values
('george',40);


Desired output:

 student | grade 
---------+-------
 george  |    40
 john    |    90
 paul    |    30
(3 rows)

Here's the code:

with ranking as
(
 select student, grade, rank() over(partition by student order by grade DESC) as place
 from 
 student_grades
)
select student, grade
from
ranking x
where 
exists (
  select null 
  from ranking
  where place <= 2
   and student = x.student 
  group by student
  having max(place) = x.place
 )

The following is shorter(works on Postgresql, Oracle) and simpler to read than above:

with ranking as
(
 select student, grade, rank() over(partition by student order by grade DESC) as place
 from 
 student_grades
)
select student, grade
from
ranking 
where (student, place) in
 (
  select student, max(place) 
  from ranking
  where place <= 2
  group by student  
 )

If only Postgres allows LIMIT clause inside an aggregation and made array_max a built-in function, this could be the shortest code:

select student, array_max( array_agg(grade order by grade desc limit 2) )
from 
student_grades
group by student;