Sunday, October 09, 2011

Just for fun, the Recurring Event "Join Now" buttons on IADN’s Webinar page automatically toggle between:

 and


You’d have to wait for a session to be about to start to see the toggle, but it toggles 5 minutes before the session starts. This avoids some confusion where folks think since there is a Join Now button, that the session will automatically start when they click the button. This way, the button is not active unless the webinar is in session, or about to be in session.


It loads a page named test.a5w every 1 minute and updates just the named DIV, not the whole page. Test.a5w contains whatever content you want to have appear:

(Click here to see where I grabbed the jquery code)

Javascript goes in the Head area:

<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
$(document).ready(function() {
$("#loaddiv").load("test.a5w");
var refreshId = setInterval(function() {
$("#loaddiv").load('test.a5w?randval='+ Math.random());
}, 60000);
$.ajaxSetup({ cache: false });
});
</script>



And then this where you want the content to appear:

<div id="loaddiv">
</div>

And here is the test.a5w page (DBF):

dim tbl as p
tbl = table.open("[PathAlias.ADB_Path]\event_item")
query.filter = "status = 'rec'"
query.order = "sortlevel"
indx = tbl.query_create()

join_yes = "<a target='_meeting' href="+tbl.url+"><img border=0 width=\"60px\" src=\"images/join_now.gif\" title=\"Join Now\"></a>"
join_no  = "<img border=0 width=\"60px\" src=\"images/join_not_now.gif\" title=\"Not in Session, check back\">"

lst = ""
tbl.fetch_first()

while .not. tbl.fetch_eof()
lst = lst + "<div class=\"adbox\" style=\"text-align:left;margin-left:5px;display: inline-table;\">"
lst = lst + "<div style=\"float:left;width:710px\"><h3 style=\"margin-top:0;margin-bottom:2px\">"+tbl.title+"</h3>"+tbl.short_desc+"<br></div>"
if dow(date()) = val(tbl.Recurring_Dow) .and. between(toseconds(time()),toseconds(tbl.recurring_starttime)-300,toseconds(tbl.recurring_endtime))
    lst = lst + join_yes
    else
    lst = lst + join_no
end if
lst = lst + "</div>"
tbl.fetch_next()
end while

tbl.close()
?lst

Tuesday, September 27, 2011

Cascading dropdowns and Primary Key field name

Best practice in Alpha Five is to name all primary keys with the table name plus "_id". E.g., the PK for the Product table would be product_id. This may be obvious to those of you who always followed that practice. But there are many developers who name their primary key "ID" for all tables (I mean I was one up to just a few days ago).

Case 1 - when creating relationships between tables in, for instance, a Linked Content Area, Alpha Five anticipates that the PK in the parent is named the same as the FK in the child. It automatically make that link for you if you have named them the same.

Case 2 - I just learned it is mandatory to follow this practice if you expect cascading dropdown features to work properly (cascade is built in to Alpha Five dropdown controls as a simple checkbox option).

If the PK and the FK are named different, the cascade will not work. Here is a graphic showing my tables names for a simple State-City cascading dropdown. Notice my field name of State_Id is the sae for both the parent and child tables.

Note that it is only important in this case that the State_Id field name is the same. I purpously did not name the PK for the City table as City_Id just to show it is not mandatory for this cascading dropdown to work. But of course, I would name it City_Id following my new rule of always naming the primary key as table_id.

Sunday, September 18, 2011

Toggle Child Grid based on value in Parent Grid

Linked Content Area Switch Model




Given
Parent table w/Grid
ChildA table w/Grid
ChildB table w/Grid
Parent has Linked Content Area with EACH Child Grid as a separate Linked Content Section

Freeform area, Linked Content placement



onRowSelect System Event
var rowNum = {Grid.Object}._selectedRow;
var cat = {grid.Object}.getValue('G','CATEGORY',rowNum);

'
'note:if your parent component is a Detail Section, the above line would be:
'var cat = {grid.Object}.getValue('D','CATEGORY');

'
switch (cat) {

case 'A':
                document.getElementById('childa').style.display = "block";
                document.getElementById('childb').style.display = "none";
                break;

case 'B':
                document.getElementById('childa').style.display = "none";
                document.getElementById('childb').style.display = "block";
                break;

default:
                document.getElementById('childa').style.display = "none";
                document.getElementById('childb').style.display = "none";
                break;
}

Notes
In my example I have only one Grid in each LinkedContent Area, but you could have any number of Grids defined per Area.

You can also use this syntax:
var rowNum = {Grid.Object}._selectedRow;

var cat = {grid.Object}.getValue('G','CATEGORY',rowNum);
if (cat=='A')
{
document.getElementById('childa').style.display = "block";
document.getElementById('childb').style.display = "none";
}
else if (cat=='B')
{
document.getElementById('childa').style.display = "none";
document.getElementById('childb').style.display = "block";
}
else
{
document.getElementById('childa').style.display = "none";
document.getElementById('childb').style.display = "none";
}



Thursday, January 28, 2010

Getting the Alpha Five Append Operation to work in web environment

One of the neat things about Alpha Five is mixing the Genie type tools on the 'desktop side' to build completed operations that you can then run from the web. Without these Genies, you would have to write the code from scratch yourself. Most of the Operations transfer over with little work. The Append Operation however takes a bit of modification. Here are instructions on how to take an Append Operation from the desktop to the web.

Click on any image for a larger view.
The process starts out by using the Genie to create an Append Operation.














Then click the "XB" icon to get the underlying code, shown below.

You simply copy-paste this to an A5W page to transfer this operation to the web.


This screen shows the code after pasting in an A5W page, but with required edits as described below:

  • Line 3-6 Optional, this is the code to purge all records from the target table. You may or may not want to do this.
  • Line 9 Changed code to use the table.open() function.
  • Line 10 Replaced the hard-coded path with the Alias, in my case [PathAlias.ADB_Path]. See an important note about this on the last image.
  • Line 11 Optional, this is debug code to write my path result, I use this method often to see my parameters.
  • Line 19 (and 21, 23, 25). Note that I removed the string "@hitsandprofiles->" from each line.These are relevant in Desktop, not in the web.

Finally, there is an important setting on the Web Publishing Panel at View | Settings | Preferences | Web Publishing that determines if your Alias (e.g.: [PathAlias.ADB_Path]) will get resolved when the files are Published or at Run Time (when someone runs your web page). If you resolve Alias at Publish Time, no need to follow these instructions. But if you resolve Alias at Run Time you MUST take these instructions in to account. In the image, line 14 uses the Alias, but line 15 uses a variable that was set using the expression:

path = filename_decode("[PathAlias.ADB_Path]")

The reason is that the table.open() function knows how to resolve the Alias, but the same is not true for the expression on line 15. There you must resolve the Alias before using it.

Sunday, November 29, 2009

Inhibit column titles if no records

Just 'discovered' another Alpha Five V10 cool feature - "supress column titles if no records". It's in the Column Titles and Sorting Options section of the Grid Properties. Neat because it has always looked messy and out of context to have a row of column titles with no values under them. Once the grid has at least one record, the column titles then appear.


Sunday, October 18, 2009

Quick way to 'check/uncheck all checkboxes'

I needed to allow my client to 'check/uncheck' all boxes in a multi-row grid. I found this very convenient code that creates a hyperlink to do simply that; add the link anywhere on the A5W page. Only thing, it checks/unchecks ALL boxes on the page, so it is only useful if you have just ONE group of checkboxes on your page.

<a href="javascript:(function(){%20function%20toggle(box){%20temp=box.onchange;%20box.onchange=null;%20box.checked=!box.checked;%20box.onchange=temp;%20}%20var%20x,k,f,j;%20x=document.forms;%20for%20(k=0;%20k<x.length;%20++k)%20{%20f=x[k];%20for%20(j=0;j<f.length;++j)%20if%20(f[j].type.toLowerCase()%20==%20%22checkbox%22)%20toggle(f[j]);%20}%20})();">Check All</a>

Wednesday, October 14, 2009

How to keep track of session variables in a web app

Almost every web application requires multiple session variables that need to be DIM'd and set to a value. A typical example might be setting "session.clientname" to the logged in user's first and last name, for convenient use when you want to display their name on a web page. Other variables are more important, like the logged-in users personal ID (commonly called the ULINK in Alpha web apps) so you can filter out just their records, and perhaps a Company_ID in a multi-tier application where you need to know their Company affiliation while logged in.

I have a standards set of session variables that go into each web app, ones I use all the time. Those are easy to keep track of, I know them by heart. But every web app also needs a host of session variables that are unique to this application. I devised the following method both to keep track of these unique session variable names and also to make it easier for me to add them as I build the application.

The normal process for adding a session variable is to add some Xbasic code either right where you first need the variable, or in a header type file that is included on ALL web pages. The later method ensures the variable is repopulated every time any page is refreshed. There is a reason you might want this, but I won't go into it right here.

Being data-driven to a fault, I now keep all of these extra session variables in a table, and use Xbasic to extract the information from that table in order to DIM and populate the value. I include a convenient checkbox to indicate if the variable is 'protected' or normal. "Protected session variable" is a term unique to Alpha Five.

Hint: click on the images below to get a larger view. If you cannot read all of the text, click this link to get it in a text file. You can also click on the image to get a larger view.

Here is the table structure:



And here is some representitive data for the table. Note that the 'expression' is normal Xbasic, exactly what you might enter directly on the A5W page to populate your variable. If you check 'Protected' it will automatically insert the text required to make the variable protected. If you include a 'Footer_ID' the current value for this variable will appear in the footer of your web application, which is good for debug purposes while you are testing the application online.


Here is the Xbasic on an A5W page I have named header_setvar.a5w. Note that there is NO HTML on this page, just the requried Xbasic. Note that I use 'evaluate_template()' to extract the information from the table. If I don't include that, the results just appear as normal text in the browser, not fired as Xbasic.

Here is the Xbasic on the individual pages to include this header_setvar.a5w. Typically this would go at the top of every A5W page. In reality, I do not place this header_setvar.a5w on individual pages, I include it another page named header_head.a5w, and that page is included on all other pages. But that is personal preference. Just the line that starts with A5W_Include is imporant here.



Here is the Xbasic that goes in the Footer.A5W page to be able to display the values for each of my session variables while testing the application. In the image below, I included some extra code that shows how I can toggle this 'debug' information off and on while online; that is the initial IF-ENDIF statement. The lines you care about to show the session variables are the two lines starting with dta3.



And here is what the footer actually looks like. It may appear to be nonsense to you, but it tells me exactly what is going on in terms of who is logged in and how that has affected the session variables. This is invaluable data while testing. When I go live, I toggle this debug information off.


Sunday, August 30, 2009

Positioning Login and toggle to show Logged-In username

This article shows how to position a Login component on a web page, and then toggle this area to show who is logged in.

The method described below requires some skill with CSS and the ability to work in the source area of an A5W page, editing HTML and XBASIC code.

This is the desired effect. A clean login component area with fields for Username, Password and also links to recover the password and "Remember Me" to allow the user to store their login for subsequent visits.

We also need to provide room for any error messages such as incorrect password, not a valid email address, etc.

And when the user has logged in, we want to hide the login fields and instead show the users name, a logout link and any information or links that pertain to their logged-in status. This is important as it indicates to the user that they are logged in.

We start with a graphic, called header.jpg in this article. Our image has a nice clearly defined login area to the right, about 110x230px with rounded edges. Our login dialog will be superimposed over this area using CSS.

Out of the box, the Alpha Five Login dialog takes up a bit too much real estate, so we need to use the Freeform area of the Login Dialog maker to reduce this. In the image below, the normal state is shown in the upper right, the desired version is in the lower left.


And here is a WYSIWYG view of the Freeform area, showing how we used a table to align the labels and flatten it just a bit for less overall vertical space.
In addition, we need to shorten several of the stock error messages. Remember, they have to fit in the graphic area I have provided. If they are too long, the message will wrap to a second line, and I just don't have room in the area I have provided. The image below shows where you can edit the Login dialog's error messages.
Insert the graphic header.jpg image where desired. Here is the CSS code I use to insert the header graphic.

#logo{
height:150px;
position:relative;
background-image: url(../images/header.jpg) ;
background-repeat:no-repeat;
}
Side note - I happen to use a header.a5w* at the top of every single page in a given web application. So, I only perform this operation once, in header.a5w. And then I use the a5w_include() function to place my header at the top of other pages in my web application.

Insert the login dialog in the A5W page.

First I create a DIV with ID=loginarea and place the normal Alpha Five login dialog code within this DIV. That's the two lines after the ELSE in the image below. Remember I also want to toggle this area when the person logs in, to show that they are logged in. So within this DIV I include an IF-ELSE-ENDIF statement.

The area above the ELSE defines the condition that someone IS logged in and shows their name and several links that would only be of use to someone who is logged in. The area below the ELSE is the normal login dialog code produced by Alpha Five when the login dialog was inserted. The only change I made was to move the line "?x_login.Output.Body.Login_Errors" below the line "?x_login.Output.Body.Login_HTML" because I happen to want my error messages to appear below the login dialog. I also used HTML 'strong' tag to highlight the error message.
Here is the section of my style sheet to format the loginarea DIV.

#loginarea{
left:0px;
top:0px;
position:absolute;
font-size:xx-small;
}

#loginarea .noneInput{
font-size:xx-small;
}

The selector is for positioning. I've chosen absolute positioning which means my loginarea DIV will be superimosed or "floating" on top of the previous DIV, my header logo. As I change the values for the left and top properties, the loginarea div will move from its default position to exactly where I want it to appear, to the far right. I also have set a property to reduce the font size in this area.

To exactly position the DIV, I use a Firefox add-on named Firebug. Here is a quick video showing how the DIV is positioned using the left and top properties: http://www.sqst.com/video/css_absolute_positioning.htm.

The second selector is used to also reduce the size of the data-entry field. This alters the font size for the class named "noneInput" which is provided by Alpha Five. I don't want to alter the size for all instances of the noneInput class, just those within the loginarea DIV.

Footnote

* I don't want to go in to it here, but I actually do not have just ONE header.a5w inserted using a5w_include(). I break my header in to two files, header_head.a5w and header_body.a5w. The first file contains only the portion of a normal A5W page that would be found in side the head tags, and the later contains only the portion that is found just past the body tag.

To help clarify, here is my basic page layout:

Thursday, February 26, 2009

Determine who's logged in

It's a common problem for a developer -- you need to reboot or reset your Alpha Five Application Server but you have one or more live applications running. If you reset the server when someone is only browsing, not too big a deal, they can continue to browse after a brief moment and may not even notice that you reset the server*. But if someone is logged in doing legitimate work, you dare not reset the server. They will lose all of their session variables and have to log back in. If they were in the middle of something important, you may have helped to create orphaned or incomplete records.

* This may not be true if have code that relies on the existence of a particular session variable or makes use of the physical session folder.

Alpha Five provides a function to count the active sessions, but that does not help because it really just counts the number of session folders. A typical web server may have dozens of session folders even if no human is viewing any page. Bots and your work as a developer will cause many session folders to be created.

So I needed to be able to know, at any moment, who is logged in. From that information I can make an intelligent decision if I can reset the server or have to wait.

When a Bot or human visits your website, a session folder is always created. I added some code to my Login.A5W page that placed a specific file in that session folder when the person logs in. The file has a particular name structure such that I can tell, just by looking at the filename, who is logged in. The file name looks like this:

loggedin__0847__admin_sqst_com__alphatogo_com_81.txt

It says that user "admin@sqst.com" logged in to website "alphatogo.com" on port 81 at 8:47AM.

To view this information, I created an A5W page that lists all of the files in all of my session folders with the name "loggedin_*.txt. Here is an example of that list. It shows the count of all session folders, the current server time, and the logged in users, three in this case:

Sessions: 22
Current__0952
loggedin__0847__admin_sqst_com__alphatogo_com_81.txt
loggedin__0949__cswatson_sentara_com__pdms_alphatogohost_com_81.txt
loggedin__0922__salesmanager_sqst_com__pdms_alphatogohost_com_81.txt

Since I know WHO is logged into WHAT application, I can make an intellegent decision on resetting the server.

If the person logs out or their session expires, that file will automatically disappear. You could enhance this by adding code on EVERY page that updated this filename showing the most recent screen refresh. I just show the original logged in time in my example.

CODE on the LOGIN.A5W page:
if eval_valid("submitbutton")
if eval_valid("userid")
dim session.__protected__userid as c
session.__protected__userid = userid
dim hst as c hst = alltrim(request.host)
filename = "loggedin"
filename = filename + "__" + time("0h0m")
filename = filename + "__" + userid
filename = filename + "__" + hst
filename = stritran(filename,".","_")
filename = stritran(filename,"@","_")
filename = stritran(filename,":","_")
filename = filename + ".txt"
save_to_file("loggedin",session.session_folder + filename)
end if
end if

CODE on the whosloggedin.A5W page:
?"Sessions: " + str(a5_count_websessions()) + "<br>"
?"Current__"+time("0h0m") + "<br>"
fpath = serversetting.document_root + "\session_folders"
filelist = filefind.get_recurse(fpath,"loggedin_*.txt",FILE_FIND_NORMAL,"N" + crlf())
dim lst as c = ""
for each foo in filelist
lst = lst + foo.value + "<br>"
next
?lst

Monday, January 19, 2009

Adding reports to the web without affecting data

Q: If you have an existing Alpha Five web application and create or edit an existing report, how do you get the new report up to the web without disturbing the existing data?

A: After you create or edit a report, three files will have been updated in your Alpha Five project for each table affected: ddd, ddm and ddx. Publish these three files up to the server using a 3rd party FTP software. Alpha's publishing option will not publish just these files. You DO NOT want to re-publish the dbf file since that will overwrite all of your data online.

At this time the report definitions should immediately be available to your web application.

Monday, February 11, 2008

some causes of high WAS CPU, robots and other information

I've been trying to resolve a high-CPU issue on my WAS. I find the WAS operating around 35% of CPU every time I visit. So I restart the WAS and watch, and it kicks back up to 35%. Here's a couple things I found:

In this specific case, the culprit was a server process named RDPCLIP.EXE. Both that and the WAS were cranked up. RDPCLIP is initiated when you run Remote Desktop and include 'local resources' such as access to the client hard disk. I killed the rdpclip.exe process, and WAS returned to normal.

------------

The second thing I looked at was my RAW log. I found one A5W page that, as shown in the RAW log, has hundreds of blank lines before the last two HTML tags. I've reported this as a bug months ago but they have been unable to fix it (during development, an A5W page will suddenly toss in dozens to hundreds of blank lines just before the last two HTML tags.) This page, when accessed on the website, causes the CPU to jump. It was in the FOOTER.A5W page, so essentially at the bottom of all of my pages.

I know that these mega-blank line pages, when opened in A5 in developer mode, can cause Alpha to crash. So I waited until I had one that did cause Alpha to crash. I uploaded that page to my WAS as the normal A5W page and accessed it via the web. It caused the CPU to go to 45% and stay there until I restarted the WAS. The solution is to check all of your A5W pages for excessive blank lines in front of the last two HTML tags and remove the blank lines, and republish. I've had to edit those files in Notepad to keep Alpha from crashing.

---------

Third is the issue of ROBOTS.TXT. Google and other web spider may hit your website looking for pages to index. They will first seek a ROBOTS.TXT file. Unless you have done something specific to allow this, the attempt will produce an error in your Error Log (if you have logs turned on at the server) such as: [Mon Feb 11 05:42:22 2008] [Forbidden] your security credentials do not allow access to this resource. In addition you will see a "403" error on a line with robots.txt in your Access log.

To rectify that (you don't have to) you need to 1) add TXT as always allowed in Web Security > Page Security > Types always Allowed, and 2) create a ROBOTS.TXT file and place it in the root directory of your application. There's plenty of help on the web on creating a robots.txt file. The proceeding assumes you are using Security Framework.
By the way, I recommend going to www.google.com/webmasters and setting up an account for each of your websites to analyze how Google indexes your site, or if it does at all.

--------

Last is the issue with FAVICON.ICO. When someone accesses your website with Foxfire or Safari (not so with IE) it will look for a FAVICON.ICO file. Same as with the robots.txt above, if it does not find it, or Security Framework prohibits access to ICO files, it will produce an error record and a 403 record in the Access log. I found one method to tell the browsers not to look for this file, but it requires you have Apache, so not applicable to most of us. The only alternative I can see is to actually make a FAVICON.ICO file and put it on your website (and include ICO as an Always Allowed file type in Security Framework.).

---------

The last thing I will mention is your own bad processes. If you find the CPU kicking up, and none of the above apply. You have to watch the performance log and other Alpha logs as you run through each process, looking for the one that kills performance. It can be anything, but typically I've found its on pages that are executing my own xbasic, and I've done something wrong. One thing I have discovered is, if I have a process that takes a long time, and one or multiple users are sitting there waiting, and eventually triple-clicking the Submit button, causing the action to be repeated, it will really bring up the CPU and start to back log the processing.

The solution I have started to put in place for this (any user-initiated process that takes too long) is to use two third party utilities to take the processing "offline" as far as the user is concerned.

With this change, the process the user initiates just saves parameters to a text file, such as 1) the name of the A5W processing page and 2) all of the entries in a dialog form, and other information. This text file goes to a particular folder on the server where it is detected by a FolderWatch program. The FolderWatch program takes the text file and uses CURL.EXE to execute the same processing the user would have initiated, but does it in the background, perhaps even waiting until the evening when activity is low.

Sunday, July 22, 2007

User Registration and Login Methods
Using Alpha Five V8 Security Framework

Today, developers can choose among several different methods to allow users to register and gain access (login) to their Internet-based application. Although some are more popular than others, the method selected should be appropriate to the nature of the online application and the type of user expected, as well as provide for application security, data security and dynamic data filtering.

The purpose of this article is to review the most popular methods for online registration and login, the individual components of those methods, and to provide a general guide to web application developers incorporating user registration and login into their applications.

Programming examples are geared towards Alpha Five version 8 deployed with the Security Framework. Because of this, you will see terms such as Security Framework, A5W and Ulink that refer directly to the Alpha Five development platform.

The full 5200 word document is available at www.alphatogo.com/learning.htm titled User Registration and Login Methods.

Here's the table of contents:

Background
- Purpose of Registration and Login
- User Registration requirements
- User Login requirements
- Examples of Registration and Login

Alpha Five
- Why is Alpha Five used here?
- Alpha Five Security Framework
- Security Groups

Registration Components
- Opt-In – Single or Double?
- Login - Email Address or non-email value?
- The Registration Form
- Security Question
- Captcha Validation
- Assigning Users to Security Groups
- Opt-out
- Terms and Conditions / Privacy Policy

Registration Models
- Open Model
- Subscription Model
- Authenticated Model
- Methods for Established Companies

Login Models
- Login Dialog- Lost password
- Lost Username
- Remember Me and Login Expiration
- Recording Logins
- Login using a Script
- Deny user access

Conclusion

Saturday, September 09, 2006

HTML in Row Labels - auto scroll to a particular position

In a Dialog or Grid, Row Labels can include HTML. Normally, your label might be something like "Customer Name", but you could add HTML tags such as <strong>Customer Name</strong> to make the label appear bold, like this: Customer Name. Obviously you can use Alpha's in-line row styles to do the same thing, but there are times when hard-coded HTML in the Row Labels (and elsewhere) are particularly useful.

For example, if you wanted your label to appear on multiple lines, you could type Customer<br>Name.

Here's another example; Customer Name<font color=#ff0000>*</font>; will yield Customer Name*, a nice way to show a field is required.

And one more - you can use bookmarks to automatically scroll the page to a particular position. If you created the same label above like this <a name="myBookmark">Customer Name</a>.

Assuming your A5W page was named Customer.a5w, then if you enter customer.a5w#myBookmark, the page will auto-scroll to that particular label position.

Tuesday, September 05, 2006

Open PDF in new window - always

A very common problem with PDF reports called from Alpha web application (or any other program) is that, by default, they open in the same browser window from where the report was called. This sets up the user to accidentally close the Alpha web application when they quite naturally click the browser's red X to close the report. Frustrating because they now have to re-log in.

I found a setting in Adobe Reader (v7) that forces all PDF's called from a browser to open in a new window. Here is how to make this setting:
  1. Open the Adobe Reader from the Windows Start button.
  2. Select Edit / Preferences and then select Internet under the Categories column.
  3. See the top most box "Display PDF in Browser" - make sure that box is unchecked.
  4. Click OK (it will take a minute to update)Try your reports again, they should open in a new window always.

The only real problem with this solution is that each individual user has to make this setting on their client machine, and you cannot effectively control this.

Tuesday, August 15, 2006

Giving Filtered Pages a Title

One method to filter data in the browser is to build the filter statement right into the URL. For example, if the URL ...Customers.A5W displays a grid showing all customer records, then ...Customers.A5W?customers_filter=State="CA" (see note below) will show just the customers in California.

When your user views this page of data, they might not know (or remember) how these records are filtered. Here's how you set a dynamic title along with your filter statement in the URL:

...Customers.A5W?title=California Customers Only&customers_filter=State="CA"

To make use of this in your A5W page, place the following xbasic where you want your title to appear:

if eval_valid("title") then
? title
else
? "My Default Title Here"
end if


That would give you a friendly title of: California Customers Only

And, although it will look a little cryptic, you could omit the title argument and just show the actual filter statement, as follows:

if eval_valid("customers_filter") then
? customers_filter
else
? "My Default Title Here"
end if


That would give you a title of State="CA".

Note - I used double quotes around the text values, but you really have to use %22 for Alpha database, as in State=%22CA%22.

Monday, August 14, 2006

Coding a "Tell A Friend" Utility

A popular item on websites and within email messages is a "Recommend Us" or "Tell A Friend" link. This is a structured way to let the viewer recommend your products or services to to one or more "friends". When they click Submit, each friend get an email that was partly scripted, and partly annotated by the viewer. A confirmation copy goes to the viewer, and a copy goes to you with a list of the referrals.

Alpha Five made this pretty simple - to get a full copy of the code required to create this utility, click here.

Note: SPAM laws dictate you cannot add these "3rd party" referrals to your standard email list without their permission. The fact that your 3rd party is, in effect, sending this email to someone they know personally, makes it legitimate. But you should structure your email such that they are inclined to opt-in in order to receive additional messages from you.

Using Alpha WAS to Track your Email Campaign

Take a look at any email in your inbox from a large company or news organization. Look at the properties of one of the hyperlinks. Rather than something simple like www.thisdomain.com/thisfile.htm, it will be more complex, like this one from TechRepublic:

http://ct.techrepublic.com/clicks?t=3D4546025-7c2bf&s=35&fs=3D0

That link has everything it needs to identify you as the person that clicked the link, which email campaign it came from, and the page that should be displayed. They could, if they wanted to, instantly send you a new email and say "Hello YOURNAME, You just clicked that link!". They don't because it is rude, and because you'd figure out they were spying on you. Rather, they are more subtle, modifying what you get in the future based on what you clicked today. By the way, even if you don't click on any link, they know you opened the email. But you knew that your email spies on you, right?

While reviewing an email tracking product, I figured out how to use Alpha WAS to do exactly the above. It was really much more simple than I imagined, and a very good exercise. Here's how:

Let's say you are using Alpha NetMailer or any other "mail merge" program to send personalized email to your Customer list. A link to your website would normally look like this:

http://www.mydomain.com/thispage.htm

To inititiate tracking, replace your hyperlink with something like this:

http://www.myalphawas.com/redir.a5w?id=12345&lnk=http://www.mydomain.com/thispage.htm

" id " is the personalized Customer_ID and " lnk " is the actual link that should open when they click the link. This is a simplistic example, normally you would want to obscure the Customer ID and Link Address so others can't determine what they really are by looking at the link. " redir.a5w " is your Alpha Five Web Server page that processes the request. The redir.a5w page is very simple, and looks like this:

if eval_valid("lnk") then
response.redirect(lnk)
else
response.redirect("
http://www.alphatogo.com")
end if

This portion just redirects the browser to the value in the "lnk" argument. Note I have a default redirection in case the value in lnk is omitted.

Now if you want to keep a record of this transaction, create a table with fields Customer and Lnk, and add this to the code:

tbl=table.open("Clicked")
tbl.enter_begin()
tbl.Customer=id
tbl.Link=lnk
tbl.enter_end()


This portion sends one record per click to a database table. The above will create a record of the Customer ID and the Link that was clicked. Useful information if you know how to use it. Your records would look something like this:

ID,LNK
12345,www.yahoo.com

The above is pretty simplistic. You would want to capture some additional information such as the date and time and the specific email campaign. Also, even though this is a good exercise, you may want to purchase a ready-made email blast program with a "Tracking" option; they really pack in a lot of charts and graphs to make the most of your email marketing efforts.

Mass Mailing Software

Alpha Five comes with a free license to use HighImpact eMail v3. This software is designed to simplify the process of sending personalized email messages to your emal list. More and more companies are using this method to carry their "brand" along with their email-based newletters, bulletins, and press releases. HighImpact has a direct link to Alpha Five databases, and so it is an easy choice for Alpha Five users.

I compared HighImpact to several other mass emailing software packages (all under $500), here is my comparison to one product, Anconia RocketSales.

Both products have you follow a similar process to send emails:

  • Create one or more email lists via import, manual entry or reading from existing tables (e.g. Alpha tables)
  • Select and then edit an email template including mail merge to personalize each email
  • Select an email list to mail to
  • Send the emails

HighImpact (www.templatezone.com) has almost a thousand very nice templates to choose from, and it is equally good at sending one email as a thousand. The program creates an icon on your email program's toolbar, making it easy to attach a fancy template to your daily emails or launch a mass mailing. They provide free internet storage (called "ReadyShare") where you can store images that are referenced in your email - you should always place images at a web location rather than embedding them directly in the email. This ReadyShare is a good idea for novice users and is fully integrated in their model. And, HighImpact has a direct link to your Alpha Five table, meaning you don't have to export your mailing list if it resides in an Alpha table.

I did have a couple problems seeing this as a business solution. Most notably is that all of the sent email ends up in your Outlook or Express Sent folder. That is fine for a few dozen emails, but not if you have a sustained campaign of hundreds or thousands. The product makes it convienient to attach stationary to your daily email correspondance. But this, in my opinion, is not a business feature as most business minded people are annoyed when receiving such fancy email formats. The fact that it links directly to your Alpha table is nice, but since there is no feature to filter the records, you have to pre-filter what is in your Alpha table. It's very common that you want to exclude some portion of, for example, your customer list. Finally, HighImpact always sends email using your default Outlook or Express profile. That means if you want to send email from "news @ mydomain.com", you have to temporarily set your default to that, and then back to your own after the mailing is done. This is easy in Express, not so easy with Outlook using Exchange.

Anconia RocketSales (www.anconia.com/rocketsales) is more suitable for business applications. It also has a suite of attractive email templates; far fewer than HighImpact, but you will end up making your own template anyway. It has its own server built in that sends the emails, so they don't end up in your Sent folder. You create the email profile right in the product, so you can send the mail "from" any address. It has a seperate field for "bounces" so all of the rejects go to your special mailbox to handle those. It does allow filtering of your email list, so you could mail to all records in California, for example. It does read existing tables via ODBC such as Alpha's DBF tables.

It also has an advanced feature to Track your email blast. This tells you exactly WHO opened your emails, and what links they clicked on. This feature is integrated into the program, and you only need to do some initial setup to get it working. It is a very neat trick as you witness, in real-time, who is opening your emails. If you are serious about your email campaign, then it is highly important that you know how effective your email blast is; and this tool helps you do just that.

If you turn tracking on, it provides a link so the reader to automatically unsubscribe. The unsubscribe can be from all emails, or they can be directed to a page where they manage their "subscriptions". For example, they could unusubscribe from Marketing, but stay subscribed to News.

I do wish RocketSales had a seperate unsubscribe table rather than flagging an existing record as "unsubscribed". I swap out email tables often enough that I would lose the unsubscribed information unless I manually process them from RocketSales tables. I will unfortunately comment that Anconia ignores email requests to their support department.

Neither product has a good built in HTML editor. If you want to create a new template, or significanly edit an existing one, you will need a 3rd party editor. I use NVU (http://www.nvu.com).

Sunday, August 13, 2006

Web Project Profiles "missing"

When you use Alpha's Send Database feature, the file \webproject\project.settings is excluded from the zip file. This file contains the settings for publishing your web project via FTP or LAN. This exclusion is most likely intentional, since the machine you are sending the project to may require different publishing settings. Plus you would not want to unintentionally give away your FTP login and password.

If you routinely send/receive projects with other machines, unless you are careful, you will eventually find your Profile settings "missing". Its not a disaster -- you have to recreate your FTP and LAN publish settings, which I always forget.

The problem only arrises when you unzip the project into a fresh directory (where there is no project.settings file). I routinely completely delete the project do this to ensure I have a clean slate, so I encounter the problem often. The solution is to retain your project.settings file when copying in a project, or being sure to send it along when you use the Send Database feature.