Multiple value input field with jQuery

Are you a Facebook or Hotmail user? You’ve probably seen those input boxes that let you input multiple email addresses or names, adding them to a list as you go along and giving you the ability to remove them later by clicking their close button… If you’re not sure what I’m talking about, they look a bit like this:

Multiple value input field with jQuery

So, having had a fairly extensive search on google for an out-of-the-box solution, it turns out there aren’t really any so I set about writing my own, using Hotmail’s for inspiration. It didn’t take many lines of code to get the job done… It’s implemented as a jQuery plugin with a little bit of CSS, which you can edit to your liking. Feel free to improve the plugin too – I haven’t checked to see if it works when applied to multiple inputs on the same page, but it works very nicely with just the one.

Here’s the code for the jQuery plugin:

[sourcecode language=”javascript”]
(function( $ ){

$.fn.multipleInput = function() {

return this.each(function() {

// create html elements

// list of email addresses as unordered list
$list = $(‘<ul />’);

// input
var $input = $(‘<input type="text" />’).keyup(function(event) {

if(event.which == 32 || event.which == 188) {
// key press is space or comma
var val = $(this).val().slice(0, -1); // remove space/comma from value

// append to list of emails with remove button
$list.append($(‘<li class="multipleInput-email"><span>’ + val + ‘</span></li>’)
.append($(‘<a href="#" class="multipleInput-close" title="Remove" />’)
.click(function(e) {
$(this).parent().remove();
e.preventDefault();
})
)
);
$(this).attr(‘placeholder’, ”);
// empty input
$(this).val(”);
}

});

// container div
var $container = $(‘<div class="multipleInput-container" />’).click(function() {
$input.focus();
});

// insert elements into DOM
$container.append($list).append($input).insertAfter($(this));

// add onsubmit handler to parent form to copy emails into original input as csv before submitting
var $orig = $(this);
$(this).closest(‘form’).submit(function(e) {

var emails = new Array();
$(‘.multipleInput-email span’).each(function() {
emails.push($(this).html());
});
emails.push($input.val());

$orig.val(emails.join());

});

return $(this).hide();

});

};
})( jQuery );
[/sourcecode]

Here’s the CSS:

[sourcecode language=”css”]
.multipleInput-container {
border:1px #ccc solid;
padding:1px;
padding-bottom:0;
cursor:text;
font-size:13px;
width:100%;
}

.multipleInput-container input {
font-size:13px;
clear:both;
width:250px;
height:24px;
border:0;
margin-bottom:1px;
}

.multipleInput-container ul {
list-style-type:none;
}

li.multipleInput-email {
float:left;
margin-right:2px;
margin-bottom:1px;
border:1px #BBD8FB solid;
padding:2px;
background:#F3F7FD;
}

.multipleInput-close {
width:16px;
height:16px;
background:url(close.png);
display:block;
float:right;
margin:0 3px;
}
[/sourcecode]

Turn a regular input into a super, jQuery-powered multiple value input like so… The names/emails entered will be submitted as a comma separated list from the original form input!

[sourcecode language=”javascript”]
$(‘#my_input’).multipleInput();
[/sourcecode]

Any questions, feel free to comment!

TPS checks much cheaper!

Our TPS and CTPS checking services have been drastically reduced.

TPS and CTPS are now just 0.1 credits per use. That’s effectively less than £1.50 per thousand numbers on our biggest credit package (1.5p per credit) which we’re sure you’ll agree is more than competitive.

Combined TPS and CTPS checking now available

We have just added a new service to T2A which compares your telephone numbers against both the Telephone Preference Service (TPS) register and Corporate Telephone Preference Service (CTPS) register. From our personal experience dealing with several clients we have found that a telephone number is occasionally registered on the incorrect list e.g. a business set up by a self employed individual may only be registered on the TPS register therefore only checking against the CTPS register would incorrectly say they are ok to call. The combined TPS and CTPS service cost 0.13 credits per use which works out as £1.95 per thousand numbers on our biggest credit package (1.5p per credit).

Prevent XSS (Cross Site Scripting) in PHP.

If your site takes card payments, chances are you need to take and pass some sort of regular security test to keep your online banking provider happy.

This is the case for us, and running most of our front end on CodeIgniter, we discovered the inbuilt xss_clean functionality, while it does actually does the job, is not enough to appease the folks who run the security scans on our sites.

So. Here is a quick function to help anyone else stuck in the same situation. The extra iteration is to deal with form submissions containing checkboxes, otherwise htmlspecialchars() would bail out with an error when we unexpectedly pass it an array instead of a string!

You just need to run this function somewhere at the start of all your code. If you’re using CodeIgniter too, pop it at the top of your MY_Controller’s constructor.

[sourcecode language=”php”]
function stopXSS() {
// prevent XSS on $_GET, $_POST and $_COOKIE
foreach ($_GET as $gkey => &$gval) {
if(is_array($gval)) { // allow for checkboxes!
foreach ($gval as $gkey2 => &$gval2) {
$gval2 = htmlspecialchars($gval2);
}
} else {
$gval = htmlspecialchars($gval);
}
}
foreach ($_POST as $pkey => &$pval) {
if(is_array($pval)) { // allow for checkboxes!
foreach ($pval as $pkey2 => &$pval2) {
$pval2 = htmlspecialchars($pval2);
}
} else {
$pval = htmlspecialchars($pval);
}
}
foreach ($_COOKIE as $ckey => &$cval) {
$cval = htmlspecialchars($cval);
}
}
[/sourcecode]

Cheaper credits!

We have recently reviewed our prices and increased the amount of credits you get on the lower credit packages.

You can now get 850 credits for £25, which is effectively 2.9p per credit. It still pays to buy in bulk if you are a heavy user as our credit packages get progressively cheaper the more you spend . Buying our biggest package is just 1.5p per credit. Why not view our pricing page now to see how this effects the service(s) you are interested in.

PHP Shortcuts Episode 2: The ternary operator

The ternary operator in PHP is basically a shorthand way of writing conditional statements, for which we would usually use the familiar if and else etc.

For example, in a program that decides what I’m going to do in my lunch hour:

[sourcecode language=”php”]
if($is_friday) {
$activity = ‘go to the pub’;
} else {
$activity = ‘stay at work’;
}
[/sourcecode]

We could write this with less code (less code is better, right?)

[sourcecode language=”php”]
$activity = $is_friday ? ‘go to the pub’ : ‘stay at work’;
[/sourcecode]

So, what happens here is if $is_friday equates to TRUE, the value after the question mark (‘go to the pub’) is assigned to the variable $activity. If $is_friday equates to FALSE then the value after the semi-colon (‘stay at work’) is assigned to $activity instead.

The other neat thing about the ternary operator is we can use it as part of an echo statement to decide what we’re doing and output it to the page in one easy line of code like so:

It's my lunch hour and today I'm going to <?php echo $is_friday ? 'go to the pub' : 'stay at work'; ?>.

Hooray for ternary operators, unfortunately it’s Thursday today so I’ll be staying at work!

PHP Shortcuts Episode 1: Simple form/query string values

Hello and welcome to my new mini blog series on PHP shortcuts. I’ll be posting some handy code snippets that I’ve used over the years that will save you both time and possibly also from Repetitive Strain Injury!

First off – A quick function to get a value from both the $_GET or $_POST arrays without potentially throwing errors by forgetting to check if your particular array key exists before trying to access it.

The old, long-winded way:

[sourcecode language=”php”]

if(isset($_GET[‘first_name’])) {
$first_name = $_GET[‘first_name’];
} else if(isset($_POST[‘first_name’])) {
$first_name = $_POST[‘first_name’];
} else {
$first_name = NULL;
}

if(isset($_GET[‘last_name’])) {
$last_name = $_GET[‘last_name’];
} else if(isset($_POST[‘last_name’])) {
$last_name = $_POST[‘last_name’];
} else {
$last_name = NULL;
}

[/sourcecode]

The new, super-quick and easy way:

[sourcecode language=”php”]

function get_post($p) {
if(isset($_GET[$p])) {
return $_GET[$p];
} else if(isset($_POST[$p])) {
return $_POST[$p];
} else {
return NULL;
}
}

$first_name = get_post(‘first_name’);
$last_name = get_post(‘last_name’);

[/sourcecode]

Job done! See you next time.

Drop down lists for iPhone: rolling your own

If like me, you’re fairly new to iPhone development, you might be wondering how to implement drop down lists in your app. The fact of the matter is that there is no native control provided by Apple, similar to the <select> tag you’ll know well if you have a background in web development. So, the solution is to roll our own: stick with me for a few minutes – I promise it’s not as tricky as it sounds. Here is how our finished control will look:

We’re going to use a UIButton control with a custom background image and put a label on top of it to show the currently selected option. Go ahead and add a UIButton and a UILabel to your view using the Interface Builder. If you’re not much of a designer, leave the background image for now and just use a regular button – it doesn’t really matter to get the code working as we need it.

Add an IBOutlet for your label to your view controller’s header file and implement the UIPickerViewDelegate and UIPickerViewDataSource delegates. We also need to define an NSMutableArray, a UIActionSheet and an NSInteger – We’ll deal with these and the delegates we are implementing in just a second. Lastly, declare an IBAction showSearchWhereOptions which we need to connect to our button in the Interface Builder. Our finished header file looks like this:

[sourcecode language=”objc”]

@interface MyViewController : UIViewController  <UIPickerViewDelegate, UIPickerViewDataSource> {

// label showing currently selected option

IBOutlet UILabel *searchWhere;

// data for populating picker view

NSMutableArray *searchWhereOptions;

// display picker view in an action sheet

UIActionSheet *actionSheet;

// keep track of selected option’s index

NSInteger selectedOption;

}

– (IBAction) showSearchWhereOptions;

@end

[/sourcecode]

Next – on to our implementation file. Implement the following methods that are required because of the delegates we have implemented.

[sourcecode language=”objc”]
– (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {

return 1;

}

– (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {

return [searchWhereOptions count];

}

– (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {

return [searchWhereOptions objectAtIndex:row];

}

// this method runs whenever the user changes the selected list option

– (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {

// update label text to show selected option

searchWhere.text = [searchWhereOptions objectAtIndex:row];

// keep track of selected option (for next time we open the picker)

selectedOption = row;

}
[/sourcecode]

Most of the work happens here.. In our showSearchWhereOptions method, which runs when the user taps our “button” (it is a button really, but it’s sneakily pretending to be a drop down list control).

[sourcecode language=”objc”]

– (IBAction) showSearchWhereOptions {

// create action sheet

actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:nil cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];

[actionSheet setActionSheetStyle:UIActionSheetStyleBlackTranslucent];

// create frame for picker view

CGRect pickerFrame = CGRectMake(0, 40, 0, 0);

// create picker view

UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame:pickerFrame];

pickerView.showsSelectionIndicator = YES;

pickerView.dataSource = self;

pickerView.delegate = self;

// set selected option to what was previously selected

[pickerView selectRow:selectedOption inComponent:0 animated:NO];

// add picker view to action sheet

[actionSheet addSubview:pickerView];

[pickerView release];

// create close button to hide action sheet

UISegmentedControl *closeButton = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObject:@"Close"]];

closeButton.momentary = YES;

closeButton.frame = CGRectMake(260, 7.0f, 50.0f, 30.0f);

closeButton.segmentedControlStyle = UISegmentedControlStyleBar;

closeButton.tintColor = [UIColor blackColor];

// link close button to our dismissActionSheet method

[closeButton addTarget:self action:@selector(dismissActionSheet) forControlEvents:UIControlEventValueChanged];

[actionSheet addSubview:closeButton];

[closeButton release];

// show action sheet

[actionSheet showInView:[[UIApplication sharedApplication] keyWindow]];

[actionSheet setBounds:CGRectMake(0, 0, 320, 485)];

}

[/sourcecode]

We haven’t yet defined our list items – we’ll do this in our viewDidLoad method. We need to make sure we set a default search option too. It’s a zero based index, so setting it to 0 will make “Specified location” our default selection.

[sourcecode language=”objc”]

// define list options

searchWhereOptions = [[NSMutableArray alloc] init];

[searchWhereOptions addObject:@"Specified location"];

[searchWhereOptions addObject:@"Near me"];

[searchWhereOptions addObject:@"Nationally"];

// default list option to select

selectedOption = 0;

[/sourcecode]

One last thing – implement the dismissActionSheet method which is responsible for hiding the action sheet when we click the done button.

[sourcecode language=”objc”]

– (void) dismissActionSheet {

// hide action sheet

[actionSheet dismissWithClickedButtonIndex:0 animated:YES];

}

[/sourcecode]

Single line addresses and names

Any API functions returning address information now include an addr_single_line field, which is a concatenated string of all the address parts, for your convenience.

Similarly, functions returning person information have a name_single_line field, which is a concatenated string of all the name parts.

Finding people at an address is now even easier

The address_person method (and the AddressPerson class in the Java/JSP library) has been augmented and the parameter “premises”, previously mandatory, is now optional.

If the premises is not entered, or does not indicate a unique address, the method returns a free (no charge) list of premises at which there is one or more person. This allows the final user to select an address from that list and to re-submit the method, using that text as the “premises” value.

This also assists with the difficulty of specifying a house name or number when the method is used with flats – a definitive list of available addresses is returned for free as an optional first stage.