Created
October 10, 2011 10:11
-
-
Save dawsontoth/1274992 to your computer and use it in GitHub Desktop.
iOS Text Field Suggestions in Appcelerator Titanium
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This demonstrates how to show suggestions on a text field using just JavaScript with Appcelerator Titanium. | |
* | |
* You will need to download four images to get this to work: | |
* | |
* 1) http://dl.dropbox.com/u/16441391/Suggest/bg.png | |
* 2) http://dl.dropbox.com/u/16441391/Suggest/[email protected] | |
* 3) http://dl.dropbox.com/u/16441391/Suggest/separator.png | |
* 4) http://dl.dropbox.com/u/16441391/Suggest/[email protected] | |
* | |
* I suggest placing them in "images/suggest/", but you can configure where they go in the "config" method. | |
* | |
* By Dawson Toth, Appcelerator Inc. | |
*/ | |
// STEP 1: Include our JavaScript module. | |
var suggest = require('suggest'); | |
suggest.config({ | |
imageDirectory: 'images/suggest/' | |
}); | |
var win = Ti.UI.createWindow({ | |
layout: 'vertical', backgroundColor: '#fff' | |
}); | |
// STEP 2: We'll define four text field in a loop, down below. | |
var fields = [ | |
'To', 'From', 'CC', 'BCC' | |
]; | |
var customerEngineers = [ 'Dawson Toth', 'Pedro Enrique', 'Jon Alter', 'Alan Leard', 'Rick Blalock', 'Matthew Congrove' ]; | |
function findCustomerEngineers(evt) { | |
var results = []; | |
// No text in the text field? That's fine, we won't show any suggestions. | |
if (evt.value.length == 0) | |
return results; | |
var searchFor = evt.value.toLowerCase(); | |
for (var p in customerEngineers) { | |
if (customerEngineers[p].toLowerCase().split(searchFor).length > 1) { | |
results.push(customerEngineers[p]); | |
if (results.length > 3) { | |
break; | |
} | |
} | |
} | |
return results; | |
} | |
for (var f in fields) { | |
// STEP 3: We need to wrap the text field in a view; the suggestions will be added to the bottom of this. | |
var wrapper = Ti.UI.createView({ | |
top: 0, left: 20, right: 20, height: 50 | |
}); | |
// STEP 4: Create the text field itself, and add it to the wrapper. | |
var text = Ti.UI.createTextField({ | |
top: 20, left: 0, right: 0, height: 30, | |
hintText: fields[f], autocapitalization: 0, | |
borderStyle: Ti.UI.INPUT_BORDERSTYLE_ROUNDED | |
}); | |
wrapper.add(text); | |
// STEP 5: Call the "bind" method of our module. | |
suggest.bind({ | |
wrapper: wrapper, | |
control: text, | |
dataSource: findCustomerEngineers | |
}); | |
// STEP 6: Add the wrapper to the window, open the window, and we're done! | |
win.add(wrapper); | |
} | |
win.open(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This module lets you set up suggestions on text fields. | |
* | |
* You will need to download four images to get this to work: | |
* | |
* 1) http://dl.dropbox.com/u/16441391/Suggest/bg.png | |
* 2) http://dl.dropbox.com/u/16441391/Suggest/[email protected] | |
* 3) http://dl.dropbox.com/u/16441391/Suggest/separator.png | |
* 4) http://dl.dropbox.com/u/16441391/Suggest/[email protected] | |
* | |
* I suggest placing them in "images/suggest/", but you can configure where they go in the "config" method. | |
*/ | |
// Instance Variables | |
var baseImageDirectory; | |
/** | |
* Allows you to customize the behavior of the module. | |
* @param args A dictionary with the following keys: imageDirectory, controls where the images are loaded from. | |
*/ | |
exports.config = function(args) { | |
baseImageDirectory = args.imageDirectory || ''; | |
}; | |
/** | |
* Sets up a text field for showing suggestions. | |
* @param args A dictionary with the following keys: control, wrapper, and dataSource. | |
*/ | |
exports.bind = function(args) { | |
if (!args.control || !args.wrapper || !args.dataSource) { | |
throw 'Not all required parameters provided: "control", "wrapper", and "dataSource" must be specified!'; | |
} | |
var visible = false, changed = false, latestValue = ''; | |
var suggestions = Ti.UI.createView({ | |
backgroundImage: baseImageDirectory + 'bg.png', | |
backgroundLeftCap: 9, | |
height: 43, | |
top: args.wrapper.size.height - 5, | |
left: 20, right: 20 | |
}); | |
var container = Ti.UI.createScrollView({ | |
left: 5, right: 5, height: 43, width: 'auto', | |
layout: 'horizontal', contentWidth: 'auto' | |
}); | |
suggestions.add(container); | |
function clickListener(evt) { | |
if (evt.source.isSuggestion) { | |
args.control.value = latestValue = evt.source.text; | |
visible = changed = false; | |
hide(); | |
} | |
} | |
var children = []; | |
var originalHeight = args.wrapper.size.height || 0; | |
function show() { | |
args.wrapper.height = originalHeight + suggestions.height - 5; | |
args.wrapper.add(suggestions); | |
} | |
function hide() { | |
args.wrapper.remove(suggestions); | |
args.wrapper.height = originalHeight; | |
} | |
function sync() { | |
if (changed) { | |
changed = false; | |
var data = args.dataSource({ source: args.control, value: latestValue }); | |
if (!data || data.length == 0) { | |
if (visible) { | |
visible = false; | |
hide(); | |
} | |
} | |
else { | |
if (!visible) { | |
visible = true; | |
show(); | |
} | |
for (var c = 0; c < children.length; c++) { | |
if (children[c].isSuggestion) { | |
children[c].removeEventListener('click', clickListener); | |
} | |
container.remove(children[c]); | |
} | |
children = []; | |
for (var i = 0; i < data.length; i++) { | |
var child = Ti.UI.createLabel({ | |
isSuggestion: true, | |
text: data[i], font: { fontSize: 14 }, | |
color: '#fff', shadowColor: '#000', shadowOffset: { x: 0, y: -1 }, | |
width: 'auto', height: 14, top: 13, bottom: 16, left: 15, right: 15 | |
}); | |
child.addEventListener('click', clickListener); | |
children.push(child); | |
container.add(child); | |
if (i != data.length - 1) { | |
var separator = Ti.UI.createView({ | |
backgroundImage: baseImageDirectory + 'separator.png', | |
width: 2, height: 36, top: 2 | |
}); | |
children.push(separator); | |
container.add(separator); | |
} | |
} | |
} | |
} | |
} | |
args.control.onChange = function(evt) { | |
if (evt.source.value != latestValue) { | |
latestValue = evt.source.value; | |
changed = true; | |
} | |
}; | |
args.control.onFocus = function() { | |
args.control.onChangeIntervalID = setInterval(sync, 1000); | |
args.control.addEventListener('change', args.control.onChange); | |
// force a refresh | |
changed = true; | |
if (visible) { | |
show(); | |
} | |
}; | |
args.control.addEventListener('focus', args.control.onFocus); | |
args.control.onBlur = function() { | |
clearInterval(args.control.onChangeIntervalID); | |
args.control.removeEventListener('change', args.control.onChange); | |
if (visible) { | |
hide(); | |
} | |
}; | |
args.control.addEventListener('blur', args.control.onBlur); | |
}; | |
/** | |
* Stops a text field from showing suggestions. | |
* @param args A dictionary with the following keys: control. | |
*/ | |
exports.unbind = function(args) { | |
if (!args.control) { | |
throw 'Not all required parameters provided: "control" must be specified!'; | |
} | |
clearInterval(args.control.onChangeIntervalID); | |
args.control.fireEvent('blur'); | |
args.control.removeEventListener('focus', args.control.onFocus); | |
args.control.removeEventListener('blur', args.control.onBlur); | |
args.control.removeEventListener('change', args.control.onChange); | |
args.control.onChange | |
= args.control.onFocus | |
= args.control.onBlur | |
= args.control.onChangeIntervalID | |
= null; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I didn't see that you coud scroll horizontally the suggestions. This allows the user to see all the suggestions, so it's fine. Your code is great : bravo