lauantai 10. elokuuta 2013

Javascript: How to send just one form element by Ajax with XMLHttpRequest 2

Because of HTML5, we have new XMLHttpRequest level 2 API and FormData-object which let us to create a custom POST data.  In this post I am not going to explain all details about new Ajax possibilities, that is done in article "New Tricks in XMLHttpRequest2".

In article written by Eric Bidelman, is explained in nice way how to create a FormData-object from particular form-element. So we can turn any form into a FormData-object by giving a form-element from DOM to FormData constructor.

var myform=document.getElementByTagName('form')[0]
var formdata=new FormData(myform);

This will create an formdata variable which can be send to server by Ajax.

What Eric does not tell in article, is that FormData object can be feeded only with Form element, and in object itself it is not possible to choose which form controls will be included and which should be left behind. This is how it different from jQuery's $.serialize or $.serializeArray, which does not care if form controls actually are inside a form element or not.

In real life, it is sometimes needed to send to the server only particular section of form or an individual form control. Lets assume we have an lonely textinput which we would like to send to an server.
<input type="text" name="address" id="myinput">

As now, it is not possible to create a FormData object, because the input is not inside a form.
However, following functions will make it happen:

function createFormData(elem) {
var dataform=document.createElement('form');
dataform.appendChild(elem.cloneNode(1));
return new FormData(dataform);
 }


With the function it is possible to create an FormData object from single input:

var inputelement=document.getElementById('myinput')
var formdata=createFormData(inputelement)


Finally we can send the input to a server:

var xhr = new XMLHttpRequest();
xhr.open('POST', 'mywebpage', true);
xhr.onload = function(e) { ... };
xhr.send(formdata);

perjantai 9. elokuuta 2013

PHP: Get list of possible foreign key values in MySql using PDO

Using foreign keys is very good way to enforce Referential integrity of database. Often it is needed to give ability to insert a record into a database from some kind of user interface, such as HTML form. When foreign keys are involved, it is needed to check that user does not insert data which does not have corresponding foreign key. We might have form which have select-element for picking the value, but to create an element we need find out where the foreign table is and which are acceptable values.

Lets assume database have two tables: Departments and Cities. Department have city-column which is foreign key pointing to cities table.

Name City
Manhattan flowersNew York City
Michigan beautyChigago
Departments
City State
New York CityNew York
ChigagoIllinois
Cities

We need to create an user interface for adding new departmens. While "city" is set to be foreign key, we need to make sure user cannot point to city which is not defined in cities table. All data related to foreign key is stored in information_schema, as base I used example written by Stefan Luv and Timo Huovinen to find out right table which hold the foreign key data. Then processed the data to find all possible values.
Lets assume you have created an PDO connection which is stored in $db variable:

$q=$db->prepare('SELECT ke.referenced_table_name assoc_table,
  ke.referenced_column_name assoc_col FROM
  information_schema.KEY_COLUMN_USAGE ke WHERE ke.referenced_table_name IS NOT NULL            
AND ke.table_schema=:database AND ke.table_name=:tablename AND ke.column_name=:col');
$q->bindValue(':database','mydatabasename'); //Set your database name here
$q->bindValue(':tablename','Departments');   //Set your table name here
$q->bindValue(':col','City');                //Set the column which foreign key values you want to have here
if($q->execute()) {
$foreingtable=$q->fetch(PDO::FETCH_ASSOC);
$q=$db->prepare('SELECT '.$foreingtable['assoc_col'].' FROM '.$foreingtable['assoc_table']);
if($q->execute())
echo json_encode($q->fetchAll(PDO::FETCH_COLUMN));
 }
else {
header('http/1.1 500 Internal Server Error');
print_r($q->errorInfo());
exit;
 }


Code below will find all possible values of column which is set to be foreign key (New York City, Chigago). It will then return it as JSON format, which may be used to create for example an drop-down list.

If you have any questions or something to add, don't hesitate to comment.

torstai 8. elokuuta 2013

Javascript: window.prompt on IE10 metro

Today some of my customers complained that they cannot fill form in one website. After investigating I soon realized that problem was lack of support for window.prompt method in IE 10 Metro mode.

I like to use window.prompt, because it is native and standard way to ask user input. It gives away the UI design to browsers, so designer does not need to care how it will be shown on different devices.

In IE 10 Metro, window.prompt is defined and the method does exist. However, user will never see prompt box and value of prompt is always undefined.

To correct the functionality in IE 10 Metro mode, I created a polyfill for it. The webpage that I used in this particular case is using jQuery Mobile framework, so I used popups from jQM it as part of the solution. I also had to alter behavior of window.prompt a little bit. Because it is impossibe to create a polyfill which will halt execution of script while waiting user input, I had to implement a callback which will be executed when user has given the input.

The code for fixing window.prompt on IE10 metro mode (Requires: jQuery Mobile 1.3)

window.cacheprompt=window.prompt;
window.prompt=function(msg,defaultvalue,callback) {
var r=window.cacheprompt(msg,defaultvalue);
if(typeof(callback)=='undefined')
return r;
if(typeof(r)=='undefined' && typeof(callback)=='function') {
var form=$.mobile.activePage[0].appendChild(document.createElement('form'));
var label=form.appendChild(document.createElement('label'));
label.appendChild(document.createTextNode(msg));
var textinput=document.createElement('input');
textinput.type='text';
label.appendChild(textinput).value=defaultvalue;
var btn=form.appendChild(document.createElement('input'));
btn.type='button';
btn.value='ok';
btn.onclick=function() {
callback(textinput.value);
$(form).popup('close');
}
$(form).popup({theme:'a'}).popup('open');
}
else if(typeof(callback)=='function')
return callback(r);
 }

The polyfill will override native window.prompt method, but wont affect behavior of it unless browser is not capable of showing the prompt window. The Polyfill adds third parameter to prompt method, a callback which will be executed when user has gave the input.

window.prompt('Your name', 'Peter Pan', function(name) {
    alert('Your name is '+name);
 })

On IE10 Metro UI it will be shown as in picture:

tiistai 6. elokuuta 2013

PHP: Magic methods and ArrayObject

On of the irritating sides of PHP is using lot of functions over methods. People familiar with javascript programming knows how easy it is for example to filter, split or join arrays. They are done with methods, while in PHP they are done with functions. Another thing which people often complain is irregular order of parameters in functions, for example array_map takes callback as first argument and an array as second, while array_walk takes an array as first argument and callback as second.

When programming with Javascript I like the fact that an array is an object, so much, that I created similar array type of object in PHP. PHP is branded to be dynamic language, in this post I test how dynamic the language can be by creating Javascript-like arrayobject. I created a class which extends ArrayObject class. ArrayObject gives ability to objects to act as array (they can go through foreach etc). With magic methods, I was able to implement all array_* functions as methods for arrayobject.

class Arr extends ArrayObject {
private $container=array();
public function __construct($arr) {
parent::__construct($arr);
$this->container=$arr;
}
public function getContainer() {
return $this->container;
}
    public function offsetSet($offset, $value) {
        if (is_null($offset)) {
            $this->container[] = $value;
        } else {
            $this->container[$offset] = $value;
        }
parent::offsetSet($offset, $value);
    }
    public function offsetUnset($offset) {
        unset($this->container[$offset]);
parent::offsetUnset($offset);
    }
public function __call($name, $args) {
if(function_exists('array_'.$name)) {
foreach($args as $key=> $ar) {
if(is_object($ar) && get_class($ar)=='Arr')
$args[$key]=$ar->getContainer();
}
set_error_handler(function($a,$b,$c,$d) {throw new Exception($b);});
try {
$ref=new ReflectionFunction('array_'.$name);
if(current($ref->getParameters())->isPassedByReference()) //walk
$newargs=array(&$this->container);
else
$newargs=array((array)$this);
foreach($args as $arg) {
$newargs[]=$arg;
}
$r=call_user_func_array('array_'.$name,$newargs);
} catch (Exception $e) {
array_splice( $args, 2, 0, array((array)$this));
$r=call_user_func_array('array_'.$name,$args);
}
restore_error_handler();
if(is_array($r))
return new Arr($r);
return $r;
}
}
 }


To use the class, all we need to do is wrap an array with Arr class:

$fruits = new Arr(array("lemon", "orange", "banana", "apple"));

Now we have $fruits arrayobject, which have all "array_*" functions as method. There are over seventy array_* functions which we can now use as method. Lets see how to use it:

$fruits->change_key_case(CASE_UPPER)->filter()->walk(function($value,$key) {
     echo $key.': '.$value."\r\n";
});

In example above, all keys in $fruits array are changed to uppercase, then empty members are filtered out, finally a function is applied to all members of an array. Now lets compare how same would be done with native array

array_walk(array_filter(array_change_key_case($fruits)),function($value,$key) {
 echo $key.': '.$value."\r\n";
 })

This seems rather interesting, as 49 lines of code change the way and idea how PHP code can be written. PHP is dynamic language after all.

lauantai 3. elokuuta 2013

PHP: Using functional programming for listing files and directories

Have you ever had situation where you need to list all specific files or folders in directory? In this post I go thought some PHP's functions which are very useful for listing files or directories.

There are several functions for listing contents of directory, scandir, readdir and glob. In this article I am going to use glob. Reason for using glob over scandir and readdir is first of all that scandir function returns file names without paths, so if we want to pass the output into some another function, it is not so safe than glob, which return file names with full or relative path. On another hand, readdir function needs directory handling resource created with opendir function, so it is unnecessary complex.

Listing files and folders is simply done with glob function:

glob('mydir/*')

Code above will create an array containing all files and directories from "mydir" directory:
Array (
    [0] => mydir/file
    [1] => mydir/images
    [2] => mydir/memo.txt
    [3] => mydir/other stuff
    [4] => mydir/page.html
)

Filtering the output

Getting only directories

You may want to filter the list to get only files or only directories. Glob-function takes second parameter a flag, which gives some possibilities of procesing the output. Using function with flag GLOB_ONLYDIR make function to return only directories

glob('mydir/*',GLOB_ONLYDIR)
Return:
Array
(
    [0] => mydir/images
    [1] => mydir/other stuff
)

Getting only files

There are no handly flag for filtering list to contain only files. However, we may use the array_filter function, which is nice way to filter the output of glop. Function takes two parameters, an array and callback function for filtering. It is easy to use PHP's is_file function is this situation. 

array_filter(glob('mydir/*'),'is_file')

We wrapped the glob function with array_filter function and gave it callback function "is_file" The output should contain just files but not directories

Array (
    [0] => mydir/file
    [2] => mydir/memo.txt
    [4] => mydir/page.html
)


There are dozen of another build in functions which can be used to filter the list, such as is_readable, is_writable and is_executable. Sometimes build in functions are not enought and you need advanced filtering, for that, we are going to use closures.

Advanced filtering with closure


Lets assume we want to have list of files, which are smaller than 30 kilobytes. To get size of file, we use filesize function.

array_filter(glob('mydir/*'),function($file) {
 return (is_file($file) && filesize($file)<30000);
})
In example above, instead of giving a name of function as second parameter for array_filter, we wrote a function. In function, we used is_file to ensure that instance is a file and filesize funtion to get size of file for comparison. Again, there are dozen of another simple functions we may use for filtering, such as fileatime, filemtime and fileperms.

Get contents of files


Many times it is needed to do something with files. Lets see how we can open each file from directory. Getting a content of file is very easy with file_get_contents function. Function takes file path as parameter, read the content and insert it into a variable.
$contents=array_map('file_get_contents',array_filter(glob('mydir/*'),function($file) { 
return (is_file($file) && filesize($file)<30000);
}));
Example above we used array_map function. The function takes two argument, an array and function. Then it applies the function to all members of array. Finally it return the modified array. As result we have $contents variable which hold content of all files in mydir-directory which are smaller than 30 kilobytes.

Closing remarks

PHP have dozen simple functions which do one task, for example is_file and file_get_contents. Combining simple functions with array handling functions such as array_map or array_filter gives lot of possibilities with just few lines of code. You might also noticed that we didn't use any loops, using functional programming gave us possibility to do complex program with just couple lines of code.