Twitter bootstrap, fly out contact or feedback form with validation and Ajax submission

Ok, I have taken a look at several of the contact or feedback forms on the internet in the past few weeks and they all work great, however, they require varying numbers of includes, and in some cases images, or even completely different versions of JQuery to get them up and running. The solutions that take advantage of HTML and the latest version of bootstrap.js are practically non-existent.  So I thought why not roll my own then pass it on, after all it comes in at six lines of JavaScript code for the toggle (I added a form validation and ajax submit for those that need help there) , some CSS, and a good old fashioned HTML form tag. At the very least will introduce you to a few JavaScript features that you may not have been used to seeing.

Ingredients

Twitter bootstap -> http://twitter.github.io/bootstrap/index.html

Let’s start with the end first (here’s what you are getting yourself into):

Screen Shot 2013-05-05 at 12.16.11 PM

I am posting the code to github as well as including it in this post, so feel free to pull it down from there and *hint* *hint* fork it and improve the validation methods if can ….  as it will probably come down in a cleaner format than cut and paste would have given you.

https://github.com/jmcdonald69124/jQuery-Bootstrap-Feedback-Sliding-Form

.rotate {
/* Safari, Chrome */
-webkit-transform: rotate(-90deg);
/* Firefox */
-moz-transform: rotate(-90deg);
/* IE */
-ms-transform: rotate(-90deg);
/* Opera */
-o-transform: rotate(-90deg);
/* Older versions of IE */
	filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
/* CSS3 standard as defined here: http://www.w3.org/TR/css3-transforms/ */
	transform: rotate(-90deg);
}
		
.required {
	background-color:#F2DEDE !important;
	border: 1px #F00 solid !important;
}
		
.feedback {
	position	: fixed; /* This will never scroll out of view */
	background-color: #2F96B4;
	border		: 5px solid #333;
	color		: #FFF;
	font-weight	: bold;
	font-size	: 16px;
	padding	: 15px;
}
		
.feedback-form-wrapper {
/*
This is the CSS for the feedback div that is fixed to the top left hand side
of the screen. 
*/
display		: block;
	z-index		: 9999; /* Make sure it floats a little higher than the feedback form div below */
	top		: 100px;	
	left		: -395px; /* Bring the div in and hide the left (top) border */
	width		: 350px;
}
		
/* This will put some distance between the input box and the next label */
.feedback input{
	margin-bottom:5px;	
}
		
.feedback legend{
	color		: #FFF;	
}
		
.feedback-toggle {
/*
This is the CSS for the feedback div that is fixed to the top left hand side
of the screen. This div should slide with the form so that it provides a 
close button when the form is slid into view.
*/
left		: -49px; /* Bring the div in and hide the left (top) border */
	left		: -10px\9; /* Less Than IE9 Hack - Bring the div in and hide the left (top) border */
	top			: 200px;
	cursor		: pointer;
	padding-left: -75px;
	width		: 90px; /* Since this is getting rotated width appears as height to the eye*/
	height		: 15px; /* Since this is getting rotated height appears as width to the eye*/
	text-align	: center;
	border-top	: 5px solid #2F96B4;
	border-left	: 4px solid #333;
	border-right: 4px solid #333;
	z-index		: 10000; /* Make sure it floats above the content */
}

Of course, before I explain it would be nice to see the HTML that this code is modifying.

<!-- 
	This is the feedback form that gets toggles in and out of view
	based on the user clicking the 'feedback_toggle' div.
-->
<!-- **************************************************************  --> 

<div class="feedback feedback-toggle rotate" >Feedback</div>
<div class="feedback feedback-form-wrapper">
<form id="feedback-form" class="form-horizontal">
      <legend>Please give us feedback .. </legend>
          	<div class="alert alert-error" 	style="display:none">
	<h4>Uh-Oh</h4> 
                    Looks like some of the required fields are not complete!
	</div>
                <div class="alert alert-success" 	style="display:none">
	<h4>Thanks!</h4> 
                    Your feedback has been submitted, we'll get back to you as soon as we can!
	</div>
                <div class="alert alert-block" 	style="display:none">
                  <h4>Warning!</h4>
                  Something happened and the form did not get submitted...
                </div>
            	<label>Name</label>
                    <input type="text" id="username"  	data-validation='{"required":true,"type":"text"}' 	name="username" class="input-block-level"   >
                <label>Email</label>
                    <input type="email" 	name="email"  	data-validation='{"required":true,"type":"email"}'  class="input-block-level"  >
                <label>Message</label>
                    <textarea id="comment" 	name="comment"  data-validation='{"required":true,"type":"text"}' 	class="input-block-level" style="margin-bottom:10px;"  rows="4" cols="30"></textarea>
                <button class="btn btn-inverse btn-large pull-right"  float="right">Send</button>
 </form>
</div>
<!-- **************************************************************  -->

And finally, the JavaScript that is needed to make all of this work:

// This is the Feedback toggle functionality it slides the feedback form in and out
// of view when the user clicks the div with the class .feedback-toggle
$('.feedback-toggle').click( function(){
	var 	left = parseFloat($('.feedback')[0].style.left.match(/[0-9]+/g)) || 49,
		tgl	 = '+=390';
	      	(left > 49)  ? tgl = '-=390' : tgl = '+=390';
		$('.feedback').animate({ left: tgl}, 500);
});
		
/*
This is the custom validation for the feedback form 
	I have left the types open in the switch statement feel free 
	to add.
*/
validate = function(form,element){
    var isValid = false, // Assume that everything starts off invalid
          fields  = $(form).find('[data-validation]'), //<-- Should return all input elements in that specific form.
         data,
         validationProps;
       $.each(fields, function(index, value){
	validationProps 	= $(value).data('validation');
  
	if(validationProps.required){
	      ($(value).val().length > 0 )? $(value).removeClass("required") : $(value).addClass("required");	
	}
					  
	if(!typeof validationProps.minlength === 'undefined' && parseFloat(validationProps.minlength) > 0){
	      ($(value).val().length > parseFloat(validationProps.minlength))? $(value).removeClass("required") : $(value).addClass("required");
  }
					  
 switch(validationProps.type)
{
	case "email":
		var re = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;  
		//console.log(validationProps.type);
		//console.log($(value).val().match(re));
		 ($(value).val().match(re))? $(value).removeClass("required") : $(value).addClass("required");	
	break;
	case "phone":
		// add code here 
	 break;
	case "numeric":
		// add code here 
	break;
	default:
	}
});
	isValid = ($(form).children().is('.required'))? false : true;	
	 (isValid)? $(form).find('.alert-error').fadeOut('fast') : $(form).find('.alert-error').fadeIn('fast') ;
	return isValid;
}
		
// This handles the on focus and on focus lost validation
$('input,textarea').on('blur', function(){
  	validate($(this).parent('form'),$(this).attr('id'));
}).on('focus', function(){
  	$(this).removeClass("required");
});
		
// This is the form submission AJAX code which also
// hides the feednack form.
		
$("#feedback-form .btn").click(function() {
	var url  	= "path/to/your/script.php", // the script where you handle the form input.
	data 	= $("#feedback-form").serialize(),
	isValid   = validate("#feedback-form");
	if(isValid){
		$.ajax({
			type	: "POST",
			url	: url,
			data	: data , // serializes the form's elements.
			success	: function(data){
				$('.feedback').find('.alert-error').fadeIn('fast');
				$('.feedback').animate({ left: '-=390'}, 500);
			},
			error	: function(data){
				$('.feedback').find('.alert-block').fadeIn('fast');
				return false;  
			}
		});
	}
	return false; // avoid to execute the actual submit of the form.
});

Ok, now for the explanation, rotate is pretty simple, as it just rotates the div that will serve as the ‘tab’ for the feedback page. It’s important to wrap your head around this concept, once the div is rotated the left hand side of the div is the bottom, the right the top, and the top the left, you get the idea, so if you want to make changes to the height, as you see it, you are making changes to the width.

The CSS

The feedback class contains the background color, font color and size, and border color / size for both the tab and the main form. The feedback form wrapper class contains the code that will be applied to a div that surrounds the actual web form, this CSS will bring the feedback form above the actual page by setting the z-index to 9999, and will position the form outside of the viewable area of the page by setting the value of left to be at -395. Notice the width is 350 pixels. To give the effect of having the tab the toggle area is raised above the form wrapper with a z-index of 10000, and is given a left that positions the top of the div (remember it’s been rotated) right off of the left hand side of the screen. There is a hack here to deal with IE versions less than 9. Ok, so now our CSS is set up and everything should be positioned right when we start to place out HTML code into the page.

The HTML

Ok, the form tag uses the bootstrap CSS class form-horizontal and has the ID feed-back form, the ID will be instrumental in the operation of this widget later on when we get into the JavaScript part of the tutorial. Under the legend tag are three DIVs that contain three different messages which we will use to indicate a successful AJAX submission, an unsuccessful AJAX submission, and finally, a problem with the required input AKA a validation error. Moving on to the input and text area elements, you will notice that they all have the class input-block-level, which also comes from the bootstrap CSS and just makes the element scale to the width of the container, and gives it that cool rounded look.

One thing that may strike you is the use of the HTML5 data attribute, and the fact that is some JSON in the value, this will be used to tell the JavaScript what type of validation should be done on each of these elements. I will explain this in the JavaScript explanation section. The button has several classes applied to it, and all of them come from the bootstrap CSS. Again, it looks cool, that’s why you decided to use it, right! Anyway, this is how you get that great button in no time flat.

The JavaScript

Ok, now for the JavaScript, which will come in and do all of the heavy lifting. First, we need to be able to slide the form into the page and back out again. The trick here is that the tab needs to be attached and needs to slide in at exactly the same time as the main form. This takes only six lines of code.

<br />
$('.feedback-toggle').click( function(){<br />
	var left = parseFloat($('.feedback')[0].style.left.match(/[0-9]+/g)) || 49,<br />
		tgl	 = '+=390';<br />
		 (left &gt; 49)  ? tgl = '-=390' : tgl = '+=390';<br />
		$('.feedback').animate({ left: tgl}, 500);<br />
});<br />

Ok, so line one we attach the function to the feedback-toggle div, nothing fancy, remember that we have the class feedback which controlled the font and background properties. Breaking these common elements out into a separate class was great in itself, but now we are going to use it to sort of tie the form to the tag by making the slide out / in code act on the feedback class. The second line gets the current value for the left hand position of the feedback DIV, the variable tgl is set by default to +=390 which will be the amount that we want to increase the CSS value of left for that DIV. The line after that contains a ternary operator which tests for left greater than 49, if that is true set tgl to -+390 otherwise, well, you know. Finally, the line $('.feedback').animate({ left: tgl}, 500); is what actually does the sliding.

Moving on we come to the custom validation part of the form, I needed to do this, because , once again, there seemed to be no good validation plugin that worked with the latest version of jQuery which is bundled with bootstrap. I plan to reuse it so it just takes the form id as a parameter, the form element is something I want to expand on in a later post. Notice the lines below:

<br />
// This handles the on focus and on focus lost validation<br />
    $('input,textarea').on('blur', function(){<br />
        validate($(this).parent('form'),$(this).attr('id'));<br />
    }).on('focus', function(){<br />
                $(this).removeClass("required");<br />
            });<br />

This code attaches the validate event to all of the textareas and input elements on the page. You could easily change it to be form specific by placing a dom selector before the first section of code. Basically, this calls the validate event on focus and on lose focus of each of those elements. The form id is being passed to the function as well as the attribute id.

Once the code hits the validate function, it checks to see if there is a value in the data attribute data-validation. The code is set up to take a JSON string that contains the basic validation settings, so far, these are:

required -> true or false

minlegth -> number only

type -> email, phone, or numeric, of which only email has been coded as of yet.

Tests are made against the values in the input elements based on the settings above, and a simple true or false boolean is returned.

Finally, the code to submit the form data is fairly straightforward, first, check to see if the form is valid before submitting, then post the values to some server side script, and display the appropriate message to the user depending on what happened with the validation and submission. If all goes well hide the form by sliding it back out.

Twitter Bootstrap & JQuery Pagination – The missing JavaScript Example

Ok, so you can find the pagination tutorial in the bootstrap documentation, and it looks great, works great, but there is one thing that is missing, the JavaScript that actually links the pagination widget to the pages that you create in your application. This article will explain in detail how you can connect the pagination widget to a series of div’s that contain well, whatever you want them to.

First, you should go to the Bootstrap page http://twitter.github.io/bootstrap/components.html#pagination and take a look at the pagination example. The code from the page above is below.

<div class="pagination">
<ul>
<li class="disabled"><a href="#">&laquo;</a></li>
<li class="active"><a href="#">1</a></li>
</ul>
</div>

That’s all there is to building the widget that provides the pagination bar on your page, and admit it looks pretty cool out of the box, but this is just the UI, there is nothing on the page to show you how to use it. Now that you have taken a look let’s set up a real world working set of div’s and the corresponding li options.

<div class="pagination-container" >

   <div data-page="1" >
    	Content for Div Number 1
   </div>
   <div data-page="2" style="display:none;">
    	Content for Div Number 2
   </div>
   <div data-page="3" style="display:none;">
    	Content for Div Number 3
   </div>
   <div data-page="4" style="display:none;">
    	Content for Div Number 4
   </div>
   <div data-page="5" style="display:none;">
    	Content for Div Number 5
   </div>

   <div class="pagination pagination-centered pagination-large" style="position:absolute; bottom:0;">
       <ul class="page_control ">
            <li data-page="-" ><a href="#" >&lt;</a></li>
            <li class="active" data-page="1">
                <a href="#" >1</a>
            </li>
            <li data-page="2"><a href="#" >2</a></li>
            <li data-page="3"><a href="#" >3</a></li>
            <li data-page="4"><a href="#" >4</a></li>
            <li data-page="5"><a href="#" >5</a></li>
            <li data-page="+"><a href="#" >&gt;</a></li>
      </ul>
   </div>

</div>

Now, let me explain what has been added to the example code from the Bootstrap page. To start things off I wrapped the content div’s as well as the pagination widget in a div named pagination-container, this step is crucial as the JQuery JavaScript will later use this as a way to find the child div tags. Next, notice the inclusion of the div’s that will contain the content you would like to switch out. Inside these tags you will have noticed that there is an attribute named data-page and each div has a numerical value starting at 1. The data attribute is a new to HTML5 and allows you to store name, value pairs inside of any HTML tag. This tag is intended to be a custom data element that should store private data for which there are no more appropriate attributes or elements. You can read more about the data attribute at w3.org. JQuery happens to have a nice set of built in methods that allow you to access and use the values that can be found in the data attribute. For an in depth look at Jquery.data() take a look at the following resource (http://api.jquery.com/jQuery.data/). After looking at the content holders , you may have noticed the inclusion of the inline style attribute on the container that holds the bootstrap.

style="position:absolute; bottom:0;"

The CSS above just positions the paginator to the bottom of the pagination-container div. This is pretty important as you want to give the appearance that the paginator is static, and it would jump when the height of the content tags change otherwise.

The changes in the li tags that make up the bootstrap paginator’s ‘buttons’ include the addition of the data attributes. After careful inspection, you notice that the data element values and name matches with the data elements that can be found on in the top level div tags.

Now let’s take a look at the script that runs the paginator. We’ll add a function in the script tags named paginationHandler, the code for the function can be found below.

var paginationHandler = function(){
	$('.page_control li').unbind('click', paginationHandler);
	var currentPage		= $(this).data('page'),
	       activePage		= $(this).parent().find('.active').data('page'),
	       num_elements 	= $(this).parent().children().length,
// This equals the first data-page value after the < button.
	       start		= 1,
 // This is the end of the actual pages, remember it is offset by the < and > buttons.
	      end			= num_elements – 2;
	if(currentPage === '+' ){
	    (activePage < end) ? currentPage = activePage + 1 : currentPage = start;
	}

	if(currentPage === '-'){
	    (activePage > start) ? currentPage = activePage - 1 : currentPage = end;
	}
// Remove the active class to the li
	$(this).parent().find('.active').removeClass('active');

// Add the active class to the appropriate li taking
        	$(this).parent().find('li[data-page*=' + currentPage + ']').addClass('active');

// Add a fade out / in effect to the div holding the
// actual data. You must have a div with the data-page
// attribute for every li tag that contains the same
// data attribute or you will get unreliable
// results.

$(this).parents("div .pagination-container").find('div[data-page*=' + activePage + ']').fadeOut('fast', function(){
       $(this).parents("div .pagination-container").find('div[data-page*=' + currentPage + ']').fadeIn('fast');
	$('.page_control li').bind('click', paginationHandler);
	});
}

Next, we have to bind the function to the li tags that reside in the div with the class .page_control. The code to do so is below.

$('.page_control li').bind('click', paginationHandler );

Now let me explain. The first line in our function unbinds the event from the li tag. This is done because if the user decides to click repeatedly on say the ‘next’ button before the fade in animation has completed then all hell will break loose and you may have several div tags displayed at one.
$(this).data(‘page’) actually gets the value in the data attribute and stores it in the current page variable. The next line goes up to the parent tag of the li that was clicked, which is of course, the ul tag and finds the element that contains the active class, and gets the value in the data element of that li tag. This gives you the active page number. The next line gets the total length of the pagination elements, so say if you wanted to make this example work for ten elements instead of five just add the li tags and div tags, no need to modify the JavaScript. Start is always going to be one and remember we have two elements that are not actually pages, they are the next and previous buttons, so deduct two from the total number of elements to get the ending page.

The two if statements handle the user pressing the next and the previous button. One feature I added was the ability to go back to start so to speak if you page past the last element, you may need to modify the code here to 1) add more elements, or 2) just stop at the end, it’s your call.

The line below removes the active class from the pagination widget, and the second line adds the active class to the new current page of the widget.

// Remove the active class to the li
$(this).parent('ul').children('.active:first').removeClass('active');

// Add the active class to the appropriate li taking
$(this).parent().find('li[data-page*=' + currentPage + ']').addClass('active');

This next piece fades out the current content div and then fades in the new content div, and last but not least, we rebind the function to the li elements so that the user can once again click the li tags and change the content.

// Add a fade out / in effect to the div holding the
// actual data. You must have a div with the data-page
// attribute for every li tag that contains the same
// data attribute or you will get unreliable
// results.

$(this).parents("div .pagination-container").find('div[data-page*=' + activePage + ']').fadeOut('fast', function(){
$(this).parents("div .pagination-container").find('div[data-page*=' + currentPage + ']').fadeIn('fast');
$('.page_control li').bind('click', paginationHandler );
});

You will need:
http://twitter.github.io/bootstrap/index.html

Importing Flat File data into SQL Server with SSIS

Ok, so one of the problems that we come across in the development field is the fact that data is not always consumable in formats that we would wish to get, it may come in tab delimited, pipe delimited, in CSV files, whatever – the main thing here is we need to automate a process that imports the data into your database that has as few moving parts as possible (so when not if you have to dig back in the code you are not left wondering how the hell you built the thing in the first place.)

Turns out it is very doable but a long drawn out process in SQL Server to build a .dtsx package that accomplishes the entire task! I have detailed the steps below as I just know that this will come back and be of use later.

 Creating a Job in SQL Server to Import Flat Files

What You Need:

Microsoft SQL Server Management Studio

MSFT SQL server

Overview:

When data comes in from outside sources in flat files that are delimited you need a way to open the files, import the data into the database, and archive the files just in case you have a need to rerun the job, or to take a look at the raw data files in the future. The script will archive the files that have already been processed in folders bearing the month and the year that corresponds with the date the job ran that kicks off the .dtsx package.

Tables:

  • processed_files – This table will hold the files that have been processed so that 1) you have a record of what has been done, and 2) if the job fails you at least know where it failed.
  • data_table – This is the table that you are importing data into and will change depending on the files that you are importing.

Steps:

  • Set up Variables
  • Set up data connections
  • Displaying and using the toolbox
  • Add Foreach Loop Container
  • Add Execute SQL Task (Check Processed)
  • Add data Flow Task
    • Add Flat File Source
    • Add Multicast
    • Add OLE DB Destination
    • Add Row Count
    • Insert Constraint between Check processed and the Import file Data Flow Task
  • Add Execute SQL Task (Register Processing)
  • Add Script Task
  • Add File System Task (Move Files)
  • Add Execute SQL Task (Update processed table)

Create processed files table:

CREATE TABLE [dbo].[file_control]

(

[ImportedFilename] [varchar](100)   NOT NULL,

[RecordsImported]  [int]            NOT NULL,

[ProcessDate]      [datetime]       NOT NULL

)

Set up Variables:

To display the variables window in Microsoft SQL Server Management Studio hover over the ‘View’ menu item then scroll down to the ‘Other Windows’ option, the resulting fly-out menu should display the variables display option.

image001

Figure 1 – View Menu Bar

The table below lists all of the variables needed to set up the file import solution on the server. These variables will be manipulated later by scripts as well as used as output and input parameters in several of the steps we are about to perform.

Name

Scope

Data Type

Value

Example

Destination Folder DTS Package Level String Archive folder. However, you will need to insert the fully qualified name to the source folder or you will get the error that is visible in Figure 2 – FilePath error is variable is left empty. Fully qualified path. End with a forward slash (\). If you are developing this on a network do not use mapped drive letters use the \\ format.
Destination Root DTS Package Level String Path to the root of the archive folder. Fully qualified path. End with a forward slash (\). If you are developing this on a network do not use mapped drive letters use the \\ format.
FilePath DTS Package Level String The path and name of the current file in the Foreach loop container. You will need to insert the fully qualified name to the source folder or you will get the error that is visible in Figure 2 – FilePath error is variable is left empty. Fully qualified path. End with a forward slash (\). If you are developing this on a network do not use mapped drive letters use the \\ format.
FilePattern DTS Package Level String The extension or name that you want to use as a filter when determining which files the Foreach loop container will process. *.txt, or SALES*.txt
MonthNameFormat DTS Package Level String The Visual basic or C# format specifier for the month part of the date. More information can be found in the script section of this document. MMMM or MMM
Processed DTS Package Level Int32 Will hold a flag that will be set to true if the file has already been processed. 0
Records DTS Package Level Int32 Will hold the record count, or the number of rows that are present on the file. 0
SourceFolder DTS Package Level String The source folder where the files that you will be processing reside. will be Fully qualified path. End with a forward slash (\). If you are developing this on a network do not use mapped drive letters use the \\ format.

image004

Figure 2 – FilePath error is variable is left empty

A word about scope:

                  Scope is very important in the processing of the files, you may be tempted to go with the thought that a variable.

Set up data connections

image006

Figure 3 – Connection Managers tab with context menu.

                  This .dtsx package will need three connections to add a data connection you will need to right click on the blank area in the ‘Connection Managers’ tab. You will need three connections:

  • New Flat File Connection
  • New File Connection
  • New OLE DB Connection

New Flat File Connection

The connection to the file is where you will have to set up the column mappings in order to get the data from the file to the table in the database. In this example give the connection the name ‘TextFile_Connection’, the rows are separated by a carriage return {CR}{LF}, the format is delimited, and there is one header row that we have to skip before we get to the actual data. See Figure 4 – Flat File Connection General Tab for a view of these settings.

The ‘Columns’ tab is a bit counterintuitive as it is not where we define the actual columns, it is where we set the column delimiter and the row delimiter for the rows that follow the header. In this instance we are dealing with a tab delimited file and each record is separated from the next by a carriage return. See Figure 5 – Flat File Connection Columns Tab for a view of these settings. You may be tempted to skip the next step, especially if the preview pane shows actual data from your input file; if you do you will miss one of the most important steps. Conversely, if you do not see any data in the preview grid after you navigate to the file you want to import then don’t worry, this is actually pretty common, you can add the columns manually in the next tab. 

The ‘Advanced’ tab, allows you to change the name of the columns as well as change the data type of the columns. If you are dealing with a data file that does not include column headers, or for some other reason you are unable to get the flat file wizard to recognize the  file you have selected you can press the ‘new’ button on the bottom of the screen to add columns to the connection manager. Make sure you rename these columns and match the data type and length to the destination database table. The Advanced tab is displayed in Figure 7 – Flat File Connection Advanced Tab.

 image008

Figure 4 – Flat File Connection General

image010 Figure 5 – Flat File Connection Columns Tab

image012

Figure 6 – A test tab delimited text file with one header row

image014

Figure 7 – Flat File Connection Advanced Tab 

New File Connection (A connection that points to the Processed Folder)

image016

Figure 8 – New File Connection dialog box

                  To set up a connection to the folder that will contain all of the archived files (in their dated folders) you will need to add a file connection. This is pretty straight forward, just change the usage type to ‘Existing Folder’ and browse to the folder on the server. Note that if you are using mapped drives you will need to type the location in the Folder textbox using the server name on this format \\servername\somefolder\destfolder.  The folder you are pointing to must exist before you complete this step.  The File Connection Manager Editor can be seen in Figure 8 – New File Connection dialog box.

New OLE DB Connection

image018

Figure 9 – New OLEDB Connection manager  window

Displaying and using the toolbox

 image019

Figure 10 – Show / Hide the Toolbox

                  The toolbox provides drag and drop elements that can be added to the control flow and data flow tabs in SQL Servers Management Studio. It is important to note that the options available within the toolbox change depending on the tab that you are working in. This distinction is usually ignored in many of the online tutorials that you will find, which in leaves the reader wondering why they do not see those options.

To display the Toolbox pane click on the view menu item then press the toolbox icon, or just use the shortcut keys Ctrl+Alt+X.

image022

Figure 11 – Toolbox when Control Flow is displayed

image024

Figure 12 – Toolbox when Data Flow is shown.

The figures above illustrate the different toolboxes. The next section will focus on the items necessary to complete the data import task.

Add Foreach Loop Container

 image026

Figure 13 – The Foreach loop Container

The Foreach loop container allows you to loop through a collection of objects. To configure the container double click on it to display the Foreach loop editor which is shown in Figure 14 – Foreach Loop Editor General Tab.

In the General tab change the Name to ‘Loop thru files’.

The next tab is the Collection tab; this is where you will be able to let the container know which directory it is supposed to loop through, as well as which files it should process. In this tab you will have to enter a value in the Folder textbox in the Enumerator configuration section of the application. The Files textbox works just like a file search in windows explorer, so if you wanted to loop through all the text files in a folder you would have to add ‘*.txt’.

The third tab is the ‘Variable Mappings’ tab, and is where we will connect the variable that is specified in the ‘Collection’ tab under the Enumerator configuration section. The variable in this instance will be set to the fully qualified file name.

Finally, in the expressions tab we will set up the variables that will hold the Directory and FileSpec values, this way we can go in later and change them by simply updating the variable’s value. To map the variables just click on the ellipsis in the right hand column of the expressions line of the Foreach Loop editor. Once the Property Expression Editor is displayed you can select a value in the right hand box that you would like to assign the variables value to.  Figure 17 – The Expressions tab of the Foreach Loop Editor shows both the Expressions tab and the Property Expression Editor.

image028

Figure 14 – Foreach Loop Editor General Tab

image030

Figure 15 – The Collection tab of the Foreach Loop Editor

image032

Figure 16 – The Variable Mappings tab of the Foreach Loop Editor

image034

Figure 17 – The Expressions tab of the Foreach Loop Editor

Add Execute SQL Task

                  When looping through the files the application will expect that the incoming data conform to the specifications that are set later in the data flow task. If for some reason the data does not conform to the specifications it will cause the entire job to stop executing. In order to determine where the job stopped running and to provide a means of restarting the job without deleting the data that was successfully input before the job failed it is important to log the file that has been processed and check that this file is not imported twice. This task will check the file log and determine if the file has been run already.

                  First drop the Execute SQL Task Control Flow Item into the Foreach loop container.  Next double click on the container to view the Execute SQL Task Editor, shown in the figure below.

image036

Figure 18 The General tab of the Execute SQL Task Editor

                  In the tab above change the name to read ‘Check Processed’. Change the result set from None to Single Row, then drop down the connection and if you have not added a connection to the database yet click on <New Connection> and add a connection to the database. Given the table structure for the processed files table found on page one place the following SQL in the SQL Statement area.

SELECT COUNT(*) AS Processed FROM file_control WHERE ImportedFilename = ?

                  Notice the question mark in the sql statement, this will receive the value in the parameter mapping tab that we will set up now. In the ‘Variable Name’ column drop down the box and select the FilePath variable that was set up earlier. Note that all variables that are user created will be prefixed with the word User and two colons (::). The directions should be Input, the Data Type is VARCHAR, and of course, this is the 0th parameter so place 0 in the Parameter Name column.  Adjust Parameter Size according to your file path size; here 200 will cover anything that is thrown at it.

 image038

Figure 19 – The Parameter Mapping tab of the Execute SQL Task Editon

                  Next click on the ‘Result Set’ tab and in the Result Name column type in ‘Processed’, and in the variable column drop down the box and select the user defined variable named User::Processed.

 image040

Figure 20 – The Result Set tab of the Execute SQL Task Editor

Add data Flow Task

 image042

Figure 21 – Data Flow Task with Context Menu visible as well as the data Flow tab visible

Next we will add the data flow task by dragging it inside the Loop thru files container. First, drag the green arrow that comes from the Check processed task that you just created to the new data Flow Task and connect the two.

Double clicking on the data Flow Task will take you to the data Flow tab pictured in the image above, which will allow you to drag and drop additional elements inside of the data flow task. The elements that are available will differ when inside the data flow tab. To rename the Data Flow Task you will have to right click on it and select Rename, at this point give the task the name ‘Import file’.

                  Next , double click the Import file task to change your view to the data Flow tab. Once inside the data flow tab we will need to drag four elements from the toolbox to the tab.         

  • Flat File Source element
  • Multicast element
  • OLE DB Destination element
  • Row Count element

After adding these elements connect them by dragging the green lines as shown in the figure below.

 image044

Figure 22 – Arraignment of elements in the Import file task 

Add Flat File Source

 image046

Figure 23 – The Connection Manager  tab of Flat File Source Editor

                  Double click on the Flat File source element to display the editor window. In the Connection Manager tab you should have the option of selecting the connection manager that points to the flat file you would like to import. You can refer to the file in Figure 6 – A test tab delimited text file with one header row for the file that we are using in this case. Once you have selected the connection move on to the ‘Columns’ section of the editor (pictured in the figure below). The Columns tab will allow you to rename the output from the file into names that actually mean something to you. Here I would suggest using the actual names in the destination table as it will make it easier to map the columns when you get to the OLE DB Destination part of this task. To change the names just click in the Output Column cell and type the name that you would like to be sent to the Multicast element. Once you complete these steps the small red X in the top right hand corner of the element should disappear. You can think of this X as an error in the compiler if you were writing code.

image048

Figure 24 – The Columns  tab of Flat File Source Editor

Add Multicast

                  The Multicast element is one of the few that does not need any changes once placed. This element will simply take the input from the Flat File Source and route it to two locations. In this instance those locations are the DB destination, to actually insert the data into the database, and the row count element to determine how many rows were inserted for logging purposes.

Add OLE DB Destination

                  The OLE DB Destination will point to the table that will receive the data from the file. The SQL to create the test table that corresponds with the test data file in Figure 6 – A test tab delimited text file with one header row is below:

CREATE TABLE [dbo].[file_import_test](

[TestColumn1] [int] NULL,

[TestColumn2] [varchar](200) NULL,

[TestColumn3] [float] NULL,

[TestColumn4] [float] NULL

)

                  First, double click on the DB connection to display the OLE DB Destination Editor (pictured in the image below).  Next, drop down the connection manager and select the connection that points to your database, which should have been set up earlier. You will want to select ‘table or View’ for the data Access Mode, and finally select the actual table where you want the file data to be routed to in the name of the table or the view dropdown box. Finally, we will map the columns from the file to the table columns. Click on the Mappings tab in the left window pane.

 image050

Figure 25 – The Connection Manager tab of the OLE DB Destination Editor

If you configured your flat file column names to match the table column names then this part will be pretty easy, just verify that they link up. If not you are left with the task of connecting the file column outputs with the table columns and then connecting them by dragging and dropping the lines between them to the correct columns. Once you complete this task the small red X in the OLE DB Destination element should disappear.

image052

Figure 26 – The Mappings tab of the OLE DB Destination Editor

Add Row Count Element

                  The row count element will count the rows that have been read from the file and store them in the variable that has been designated in the custom properties section of the Component properties tab pictured below. All that needs to be done here is the variable User::Records should be selected from the drop down box in the column next to variable name.

image054

Figure 27 – The Advanced Editor for Row Count

Insert Constraint between Check processed and the Import file Data Flow Task

The final step in the addition of the Import file data flow task is to set up a constraint between the check processed SQL task and the data flow itself. The constraint will make sure that duplicate records do not get inserted into the table. To accomplish this double click the green arrow that connects the two elements to display the Precedence Constraint Editor.

image056

Figure 28 – Precedence Constraint Editor

                  In the window pictured above change the drop down box from the default setting of Constraint to Expression and Constraint. Once this has been completed the Expression text box will open where you enter @Processed == 0, which corresponds to the variable being passed by the Check processed SQL task. Leave the default setting in Multiple Constrains where it is and press OK. 

Add Execute SQL Task (Register Processing)

Next , drag another Execute SQL task element to the Foreach Loop Container and drop it inside the container directly under the data flow task. Right click on the task and rename it ‘Register Processing’.

image054

Figure 29 – The General tab of the Execute SQL Task Editor

                  In the General tab of the Execute SQL task Editor select the database connection from the connection dropdown box. In the SQL Statement text area insert the following SQL:

INSERT INTO file_control (ImportedFilename, RecordsImported) VALUES (?, ?)

image060

Figure 30 – The Parameter Mapping tab of the Execute SQL Task Editor

                  Next click on the parameter mapping tab and add the following parameters to the window on the right hand side, 1) User::FilePath with a direction of Input and a datatype of VARCHAR and a size of 200, and 2) User::Records with adirection of Input and a type of LONG and a size of -1. The parameter name of the first variable is 0 and the parameter name of the second variable is 1.

Add Script Task

Next drag the Script Task element from the toolbox and drop it directly under the Register Processing SQL task.  Right click on the element and give it the name Set Destination. Double click on the element to display the Script Task Editor window.  Make sure the Script language is set to Microsoft Visual Basic 2008 then press the Edit Script … button at the bottom of the window to bring up the code editor. The script that will create archive directories is below and will need to replace the code that is between the following lines:

Public Sub Main()

…..

End Sub

<b>Microsoft Visual Basic 2008 Code</b>

Dim varCollection As Variables = Nothing

Dts.VariableDispenser.LockForRead("User::FilePath")

Dts.VariableDispenser.LockForRead("User::DestinationRoot")

Dts.VariableDispenser.LockForRead("User::MonthStartPosition")

Dts.VariableDispenser.LockForRead("User::MonthNameFormat")

Dts.VariableDispenser.LockForWrite("User::DestinationFolder")

Dts.VariableDispenser.GetVariables(varCollection)

Dim SourceFilePath As String = varCollection("User::FilePath").Value.ToString()

Dim FileName As String = SourceFilePath.Substring(SourceFilePath.LastIndexOf("\") + 1)

Dim DestinationRoot As String = varCollection("User::DestinationRoot").Value.ToString()

Dim MonthStartPosition As Integer = Convert.ToInt32(varCollection("User::MonthStartPosition").Value)

Dim MonthValue As Integer = 0

Dim Yearvalue As Integer

Dim MonthNameFormat As String = varCollection("User::MonthNameFormat").Value.ToString()

Dim FolderName As String = String.Empty

Dim MonthwiseDirectory As String = String.Empty

MonthValue = Month(Now())

Yearvalue = Year(Now())

If FileName.Length > 0 AndAlso MonthValue > 0 Then

FolderName = New DateTime(1, MonthValue, 1).ToString(MonthNameFormat) & " " & Yearvalue

End If

MonthwiseDirectory = System.IO.Path.Combine(DestinationRoot, FolderName)

If Not System.IO.Directory.Exists(MonthwiseDirectory) Then

System.IO.Directory.CreateDirectory(MonthwiseDirectory)

End If

varCollection("User::DestinationFolder").Value = MonthwiseDirectory

Dts.TaskResult = ScriptResults.Success

The code above will create a folder structure for archiving the files that have been processed using a month / year naming convention as shown in Figure 31 – Example of the Archived File Structure.

image062

Figure 31 – Example of the Archived File Structure

                  The parent folder for these monthly folders is determined by the value in the variable DestinationFolder.

Add File System Task (Move Files)

 image064

Figure 32 – File System Task Editor General Settings Tab

                  Next drag a File System Task element from the toolbox and drop it inside the Foreach Loop Container under the Script Task then connect the greed arrow from the Script Task to the File System Task. Right click on the element and rename it Move Files. This will be the element that physically moves the files to the archive location.

To move the processed files change the following settings in this order, or it will not work:

Destination Connection Section

  • IsDestinationPathVariable = true, this in turn changes the text in the box below it from Destination Connection to DestinationVariable
  • DestinationVariable = User::DestinationFolder
  • OverwriteDestination  =false

Source Connection Section

  • IsSourcePathVariable = true, this in turn changes the text in the box below it from SourceConnection to SourceVariable
  • Sourcevariable = User::FilePath

Add Execute SQL Task (Update processed table) 

                  The last task that you have to complete before setting up the job that will kick off this entire process is to drag an Execute SQL Task element to the Foreach Loop Container and drop the element directly below the Move Files element that you just completed. Right click on the object and rename it ‘Update processed table’, as the name suggests this task will actually go out and rename the files appending the word processed to the imported file name so that the application will not skip the file when it is dropped in the new file location tomorrow (this assumes that you are working on files that will be coming in using the same name every day which is very common!).  You should be getting pretty good at the SQL Task object by now so here are the steps required to update the file names.

 image065

Figure 33 – Your completed .dtsx package should look like this

Visual Basic and C# date Time Format Specifiers:

http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx?cs-save-lang=1&cs-lang=vb#code-snippet-2

What! A month off

You may have noticed a month lag between posts, or more likely you didn’t and I was just giving myself more credit than was due. I have spent the past month enjoying Thanksgiving, Christmas, and coding an update to the TakeStock app that I originally released in response to the first Sencha contest. I wanted to use the command line tools, see if there were any improvements in local storage, as last time around I had to fall back on SqlLite to get the data stored locally on the client machine. I also wanted to take a small stab at skinning an app using SASS and SCSS. Of course, I am now nearing the end of this experiment and have had some time to gather everything together in a presentation designed to give you all the resources you will need to build your first Sencha Touch app in one place. Here’s the post:

http://bit.ly/TFkRFe

 

Saving SVG to PNG on your cold fusion server

I built a client side javascript SVG to PNG converter that works on *modern* browsers, however, depending on your target audience the browsers that frequent your site may be less than modern – i.e. IE. In this situation you only have one option, convert the image on the server side and then render it using the good old image tag.

First, cold fusion ships with some outdated batik files (which handle the cfimage tag) , so you will need to update those first, and add the missing files that will add your svg to -> image processing ability. I used the steps found in this post to accomplish the task; I’ll list them here in short format so you can get into the ext chart part of this project.

  1. Stop your cold fusion service
  2. Download the files from the batik website http://xmlgraphics.apache.org/batik/download.cgi
  3. Rename the jar files in /wwwroot/WEB-INF/cfform/jars/  that start with batik by adding the extension .old
  4. Copy the batik jar files into /wwwroot/WEB-INF/lib
  5. Restart Cold Fusion

Next, let’s assume that we have two files, one called convertImage.cfm and one called convertImage.cfc, of course, we want to pass the svg markup to the cfm which will pass the data to the cfc for processing.

<cfcase value="saveChart">
        <cfset saveChart = data.saveChart( svg=form.svg) />
        <cfset json = "{'success':'#saveChart#'}" />
</cfcase>

The code below goes in the cfc file.

<cffunction name="saveChart" >
        <cfargument name="svg" />
            <cftry>
            <cfset svgFile = "c:\websites\temp.svg" />
            <cfset jpgFile = replace("c:\websites\temp.svg", ".svg", ".jpg") />
            <cfset pngFile = (pngPath) />--->
            <cffile action="delete" file="c:\websites\temp.jpg" >

	<cfif FileExists(svgFile)>
            	<cffile action="delete" file="c:\websites\temp.svg" >
            	<cffile action="write" file="c:\websites\temp.svg" output="#svg#" >
           <cfelse>
           	<cffile action="write" file="c:\websites\temp.svg" output="#svg#"  >
           </cfif>

            <cfset t = createObject("java", "org.apache.batik.transcoder.image.JPEGTranscoder").init() />
            <cfset svgURI = createObject("java", "java.io.File").init(svgFile).toURL().toString() />
            <cfset input 	= createObject("java", "org.apache.batik.transcoder.TranscoderInput").init(svgURI) />
            <cfset ostream 	= createObject("java", "java.io.FileOutputStream").init(jpgFile) />
            <cfset output 	= createObject("java", "org.apache.batik.transcoder.TranscoderOutput").init(ostream) />
            <cfset t.transcode(input, output) />
            <cfset ostream.flush() />
            <cfset ostream.close() />

            <cfcatch type="any">
          		 <cfreturn "false" />
            </cfcatch>
            </cftry>
        <cfreturn "true" />
    </cffunction>

The function below would go in your javascript controller.

   saveChart: function(me){
        this.dTask.delay(500, function(){
                var svg = me.up('panel').down('chart').save(
                    {
                        type    :'image/svg+xml'
                    }
                );

                Ext.Ajax.request({
                    url: 'convertImage.cfm?remoteEvent=saveChart',
                    params: {
                        svg: svg
                    },
                    success: function(){
                        // process server response here
                        window.open('temp.jpg');
                    }
                });
        });
    },