I am trying to modify the following titanium Widget.
https://github.com/pablorr18/TiFlexiGrid
It is a photo gallery, where you can fetch remote images and store it in a gallery. See this question for a background to what the problem is:
Modifying widgets in an alloy project
The trouble I am having is that, like the poster in that thread said, I am unable to get the variable passed (in this case image URL) to my controller using callback functions. In Widget.JS, at the bottom of the file, I added the following code:
Widget.xml
<Alloy>
<View id="fgMain">
<Button title="Click me!" onTouchend="buttonClicked"/>
<View id="fgWrapper">
<ScrollView id="fgScrollView"/>
</View>
</View>
</Alloy>
Widget.js
// This will hold our callback
var onClickCallback;
// The button has been clicked, call callback
function buttonClicked(e) {
if(typeof(onClickCallback) === 'function') {
onClickCallback({ type:'clicked!' }); }
}
// Assign our callback
function onClick(callback) {
onClickCallback = callback;
};
// Make the onClick function public
exports.onClick = onClick;
I was then hoping to go into my main app and get the values from the callback function like this:
photoGallery.xml
<Alloy>
<Window>
<Widget id="myWidget" src="myWidget" />
</Window>
</Alloy>
photoGallery.js
// Now we can intercept the click within the widget
// and use the values passed
$.myWidget.onClick(function(e) {
alert(e.type);
});
The trouble is, as the onTouchend event did not fire, I was unable to pass the variable to the controller which inherits the widget as the callback functions are not set.
The original widget.js code is as follows:
exports.createGrid = function(args){
var params = args || {};
//Ti.API.info('Params es ---> '+ JSON.stringify(params));
var columns = params.columns || 4;
var space = params.space || 5;
var data = params.data || {};
var options = params.params || {};
var layout = params.layout || 'gallery';
var screenWidth = params.width || Ti.Platform.displayCaps.getPlatformWidth();
if (OS_ANDROID) {
screenWidth /= Ti.Platform.displayCaps.logicalDensityFactor;
}
var newWidth = screenWidth - space;
var columnWidth = (newWidth / columns) - space;
var frameBGcolor = options.backgroundColor || '#fff';
//ADJUST THE SCROLLVIEW
$.fgScrollView.left = space;
$.fgScrollView.top = space;
$.fgScrollView.right = -1;
$.fgMain.backgroundColor = frameBGcolor;
for (var x=0;x < data.length; x++){
var frame = Ti.UI.createView({
width:columnWidth,
height:columnWidth,
backgroundColor:options.gridColor || '#eee',
top:0,
left:0,
right:space,
bottom:space
});
var overlay = Ti.UI.createView({
width:Ti.UI.FILL,
height:Ti.UI.FILL,
backgroundColor:'transparent',
zIndex:1,
strImage:data[x].image
});
var gridElement;
//TYPE OF LAYOUT
switch(layout){
case('gallery'):
gridElement = Widget.createController('gallery',{
image:data[x].image,
title:data[x].title,
width:columnWidth,
padding:options.padding || 10,
showTitle:options.showTitle || false
}).getView();
overlay.addEventListener('click',function(e){
exports.openModal(e.source.strImage);
});
break;
case('customView'):
gridElement = data[x];
break;
}
frame.add(gridElement);
// This condition makes the overlay not be added if it's not gallery layout.
// It's used to make the custom view, caputre the click method. If not,
// The overlay is on top of it and captures the click.
if(layout == 'gallery')
frame.add(overlay);
$.fgScrollView.add(frame);
};
};
exports.openModal = function(url){
var overlay = Ti.UI.createView({
width:Ti.UI.FILL,
height: Ti.UI.FILL,
backgroundColor:'#000',
opacity:0,
zIndex:100
});
var topView = Ti.UI.createView({
width:Ti.UI.FILL,
height: Ti.UI.FILL,
zIndex:1200,
visible:false
});
//this gets image , adds it to top view
var imgView = Ti.UI.createImageView({
image: url,
width:Ti.UI.SIZE,
height: Ti.UI.SIZE
});
//add it
topView.add(imgView);
$.fgMain.add(overlay);
if (OS_IOS){
//ANIMATION OF OVERLAY
overlay.animate({opacity:0.7,duration:200});
//ANIMATION FOR POP EFFECT
var t = Titanium.UI.create2DMatrix();
t = t.scale(0);
var a = Titanium.UI.createAnimation();
a.transform = t;
a.duration = 200;
$.fgMain.add(topView);
topView.animate(a);
a.addEventListener('complete', function(){
topView.visible = true;
var t2 = Titanium.UI.create2DMatrix();
t2 = t2.scale(1.2);
topView.animate({transform:t2, duration:200},function(e){
var t4 = Titanium.UI.create2DMatrix();
t4 = t4.scale(1.0);
topView.animate({transform:t4, duration:200});
//alert('animation complete');
//hide cancel button
});
});
}
else{
//ANIMATION OF OVERLAY
overlay.animate({opacity:0.7,duration:200},function(e){
topView.visible = true;
$.fgMain.add(topView);
});
}
topView.addEventListener('click',function(e){
if (OS_IOS){
var t3 = Titanium.UI.create2DMatrix();
t3 = t3.scale(1.2);
var a2 = Titanium.UI.createAnimation();
a2.transform = t3;
a2.duration = 200;
topView.animate(a2);
a2.addEventListener('complete', function(){
var t5 = Titanium.UI.create2DMatrix();
t5 = t5.scale(0);
topView.animate({transform:t5, duration:200},function(e){
$.fgMain.remove(topView);
overlay.animate({opacity:0,duration:200},function(e){
$.fgMain.remove(overlay);
});
});
});
}
else{
$.fgMain.remove(topView);
overlay.animate({opacity:0,duration:200},function(e){
$.fgMain.remove(overlay);
});
}
});
};
exports.clearGrid = function(){
$.fgScrollView.removeAllChildren();
};
From looking at it, the only way it seems to get an event handler to register is to put it one of the functions (createGrid) and call it like this:
exports.createGrid in widget.xml
var button = Titanium.UI.createButton({
title : 'Use Picture',
top : 10,
width : 100,
height : 50
});
button.addEventListener('click',function(e)
{
Titanium.API.info(url);
//do not want to store in global variable
Alloy.Globals.urlFromGal = url;
});
//add it
topView.add(imgView);
topView.add(button);
$.fgMain.add(overlay);
However I am not sure how to adapt that code to this:
// This will hold our callback
var onClickCallback;
// The button has been clicked, call callback
function buttonClicked(e) {
if(typeof(onClickCallback) === 'function') {
onClickCallback({ type:'clicked!' }); }
}
// Assign our callback
function onClick(callback) {
onClickCallback = callback;
};
// Make the onClick function public
exports.onClick = onClick;
So that I am able to access the url variable outside of the widget.js scope. I could use GLOBAL Variables - by that store the variable in one instead for this task, however I want to avoid doing things this way.
UPDATE:
Unable to get it working, but I have added the callback into an event handler. Got the event handler to fire, but not sure how to pass the callback data to onClick function:
var onClickCallback;
exports.createGrid = function(args){
var params = args || {};
//Ti.API.info('Params es ---> '+ JSON.stringify(params));
var columns = params.columns || 4;
var space = params.space || 5;
var data = params.data || {};
var options = params.params || {};
var layout = params.layout || 'gallery';
var screenWidth = params.width || Ti.Platform.displayCaps.getPlatformWidth();
if (OS_ANDROID) {
screenWidth /= Ti.Platform.displayCaps.logicalDensityFactor;
}
var newWidth = screenWidth - space;
var columnWidth = (newWidth / columns) - space;
var frameBGcolor = options.backgroundColor || '#fff';
//ADJUST THE SCROLLVIEW
$.fgScrollView.left = space;
$.fgScrollView.top = space;
$.fgScrollView.right = -1;
$.fgMain.backgroundColor = frameBGcolor;
for (var x=0;x < data.length; x++){
var frame = Ti.UI.createView({
width:columnWidth,
height:columnWidth,
backgroundColor:options.gridColor || '#eee',
top:0,
left:0,
right:space,
bottom:space
});
var overlay = Ti.UI.createView({
width:Ti.UI.FILL,
height:Ti.UI.FILL,
backgroundColor:'transparent',
zIndex:1,
strImage:data[x].image
});
var gridElement;
//TYPE OF LAYOUT
switch(layout){
case('gallery'):
gridElement = Widget.createController('gallery',{
image:data[x].image,
title:data[x].title,
width:columnWidth,
padding:options.padding || 10,
showTitle:options.showTitle || false
}).getView();
overlay.addEventListener('click',function(e){
exports.openModal(e.source.strImage);
});
break;
case('customView'):
gridElement = data[x];
break;
}
frame.add(gridElement);
// This condition makes the overlay not be added if it's not gallery layout.
// It's used to make the custom view, caputre the click method. If not,
// The overlay is on top of it and captures the click.
if(layout == 'gallery')
frame.add(overlay);
$.fgScrollView.add(frame);
};
};
exports.openModal = function(url){
var overlay = Ti.UI.createView({
width:Ti.UI.FILL,
height: Ti.UI.FILL,
backgroundColor:'#000',
opacity:0,
zIndex:100
});
var topView = Ti.UI.createView({
width:Ti.UI.FILL,
height: Ti.UI.FILL,
zIndex:1200,
visible:false
});
//this gets image , adds it to top view
var imgView = Ti.UI.createImageView({
image: url,
width:Ti.UI.SIZE,
height: Ti.UI.SIZE
});
var button = Titanium.UI.createButton({
title : 'Use Picture',
top : 10,
width : 100,
height : 50
});
button.addEventListener('touchend',function(e)
{
//Titanium.API.info(url);
if(typeof(onClickCallback) === 'function') {
onClickCallback({ type:'clicked!' }); }
});
//pass callback, not working
onClick();
//add it
topView.add(imgView);
topView.add(button);
$.fgMain.add(overlay);
if (OS_IOS){
//ANIMATION OF OVERLAY
overlay.animate({opacity:0.7,duration:200});
//ANIMATION FOR POP EFFECT
var t = Titanium.UI.create2DMatrix();
t = t.scale(0);
var a = Titanium.UI.createAnimation();
a.transform = t;
a.duration = 200;
$.fgMain.add(topView);
topView.animate(a);
a.addEventListener('complete', function(){
topView.visible = true;
var t2 = Titanium.UI.create2DMatrix();
t2 = t2.scale(1.2);
topView.animate({transform:t2, duration:200},function(e){
var t4 = Titanium.UI.create2DMatrix();
t4 = t4.scale(1.0);
topView.animate({transform:t4, duration:200});
//alert('animation complete');
//hide cancel button
});
});
}
else{
//ANIMATION OF OVERLAY
overlay.animate({opacity:0.7,duration:200},function(e){
topView.visible = true;
$.fgMain.add(topView);
});
}
topView.addEventListener('click',function(e){
if (OS_IOS){
var t3 = Titanium.UI.create2DMatrix();
t3 = t3.scale(1.2);
var a2 = Titanium.UI.createAnimation();
a2.transform = t3;
a2.duration = 200;
topView.animate(a2);
a2.addEventListener('complete', function(){
var t5 = Titanium.UI.create2DMatrix();
t5 = t5.scale(0);
topView.animate({transform:t5, duration:200},function(e){
$.fgMain.remove(topView);
overlay.animate({opacity:0,duration:200},function(e){
$.fgMain.remove(overlay);
});
});
});
}
else{
$.fgMain.remove(topView);
overlay.animate({opacity:0,duration:200},function(e){
$.fgMain.remove(overlay);
});
}
});
};
exports.clearGrid = function(){
$.fgScrollView.removeAllChildren();
};
// Assign our callback
function onClick(callback) {
onClickCallback = callback;
alert(onClickCallback);
};
// Make the onClick function public
exports.onClick = onClick;