Introduction
Today, many comparator sites give the possibility to assign a mark to a product or a service. Several controls can be used to do this. Today I submit mine: the webstarcontrol.
The big advantage to my program is that you can put several controls on the same page and you manage them as you want. The webstarctrl has 2 modes:
- Edit mode: The website visitor who assigns the mark can select his/her own mark.
- Read mode: The website visitor watches the average mark (represented by stars). He is just an observer of the mark.
This code allows you to easily integrate a very simple mark system on your website. It's useful because it is very simple to parametrize.
Background
To use this control, you need to provide parameters:
InternalId
is required and each control must have a unique ID (like ID property) ImgScrOk
is the path of the picture when selected. It's a required property ImgScrKo
is the path of the picture when not selected. It's a required property NbrStar
is the maximal mark you can give. It's a required property IsReadOnly
displays the control in consultation (without handling an event click) when it takes the true value. It's an optional property. InitialValue
select a number at the initialisation of the control.
Using the Code
To use this control, you must add three things on your project:
- the
CtrlStar
webcontrol class (CtrlStar.cs). - the JavaScript file starhelper.js. (the path of this file is parametrized on the
OnInit
method of the CtrlStar.cs file. - the pictures you want to display parametrized on
ImgScrOk
and ImgScrKo
properties.
The main difficulty I encountered in developing this control was to be able to separate all the instances of the controls in one page. The JavaScript file allows us to dynamically generate HTML, and it builds its different HTML Objects with concatenation of the internalId to separate each control. IE and its other brothers don't have the same JavaScript implementation, and you must write different code for each brother.
function BuildStars(pStarNumber , pIdDivContainer , pImgScrOk , pImgScrKo, pReadOnly ,
pInitValue)
{
if(pImgScrKo == '')
{
alert('You must specify the image path KO');
return ;
}
if(pImgScrOk == '')
{
alert('You must specify the image path OK');
return ;
}
if(pStarNumber == '')
{
alert('You must specify stars number');
return ;
}
if(pIdDivContainer =='')
{
alert('You must specify the div Id Container');
return ;
}
if(! document.getElementById(pIdDivContainer))
{
alert('Not found div Id in document');
return;
}
var i;
var idContainer = document.getElementById(pIdDivContainer);
var table = document.createElement('table');
table.setAttribute('id', 'table'+pIdDivContainer);
table.setAttribute('border','0');
idContainer.appendChild(table);
var tbody = document.createElement('TBODY');
table.appendChild(tbody);
var tr = document.createElement('tr');
tr.setAttribute('id',"tr"+pIdDivContainer);
tbody.appendChild(tr);
for( i = 0 ; i < pStarNumber ; i++)
{
var td = document.createElement('td');
td.setAttribute('id', 'td'+pIdDivContainer+i);
var hlink = document.createElement('a');
hlink.setAttribute('id', 'a'+pIdDivContainer+i);
var nb = i+1;
if( IsIE() )
{
hlink.attachEvent("onclick", function(e){
var varIdValue;
var Obj;
if( !e) e = event;
if( e.target)
{
Obj= e.target;
}
else
{
Obj = e.srcElement;
while(Obj.parentNode)
{
Obj= Obj.parentNode;
if( Obj.tagName == "A")
{
varIdValue = Obj.id;
}
}
}
var nbr = 1 + pIdDivContainer.length;
var idValue = varIdValue.substr(nbr , varIdValue.length - nbr);
idValue ++;
setStar(idValue , pStarNumber , pIdDivContainer,pImgScrOk,
pImgScrKo);
}
)
}
else
{
hlink.setAttribute("onclick","setStar("+nb+","+pStarNumber+",
'"+pIdDivContainer+"','"+pImgScrOk+"','"+pImgScrKo+"')");
}
var imgo = new Image();
imgo.id='img'+pIdDivContainer+i;
if(pInitValue > 0)
{
if(nb <= pInitValue)
{imgo.src=pImgScrOk;}
else
{imgo.src=pImgScrKo;}
}
else
{imgo.src=pImgScrKo;}
imgo.border='0';
tr.appendChild(td);
if(pReadOnly == '0')
{
td.appendChild(hlink);
hlink.appendChild(imgo);
}
else
{
td.appendChild(imgo);
}
}
var currentSelected = document.createElement('input');
currentSelected.id='hiddenVal'+pIdDivContainer;
currentSelected.setAttribute('type','hidden');
if(pInitValue > 0)
{
currentSelected.setAttribute('value',pInitValue);
}
else
{currentSelected.setAttribute('value','0');}
idContainer.appendChild(currentSelected);
}
The star click event is handling on the JavaScript function setStar
and this function call the method client setCurrentNumber
whose trigger is a Server side AJAX CallBack.
function setStar(pNumber,totalStar,IdDivContainer,pImgScrOk,pImgScrKo)
{
var i;
for(i=0 ; i < pNumber ; i++)
{
if(document.getElementById('img'+IdDivContainer+i))
{
var curImg = document.getElementById('img'+IdDivContainer+i);
curImg.src = pImgScrOk;
}
}
for(i=pNumber ; i <= totalStar ; i++)
{
if(document.getElementById('img'+IdDivContainer+i))
{
var curImg = document.getElementById('img'+IdDivContainer+i);
curImg.src = pImgScrKo;
}
}
divContainer = document.getElementById(IdDivContainer);
oldNode = document.getElementById('hiddenVal'+IdDivContainer);
var currentSelected = document.createElement('input');
currentSelected.id='hiddenVal'+IdDivContainer;
currentSelected.setAttribute('type','hidden');
currentSelected.setAttribute('value',pNumber);
divContainer.replaceChild(currentSelected,oldNode);
setCurrentNumber(pNumber,IdDivContainer);
}
To use AJAX Functionality, Pages and/or Controls, you must implement the ICallBackEventHandler
interface defining methods GetCallbackResult()
and RaiseCallbackEvent()
Server side. You need to "connect" the Client side call to the server side on the OnInit
Control method.
public class CtrlStar : WebControl, ICallbackEventHandler
{
...
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
StreamReader fp = File.OpenText(Page.Server.MapPath("~/") + "\\js\\" +
"starhelper.js");
string js = fp.ReadToEnd();
fp.Close();
Page.ClientScript.RegisterClientScriptBlock(
this.GetType(),
"scrManager",
js.ToString(),
true);
string ReferenceVersFonctionClienteInitiatriceDuCallBack =
Page.ClientScript.GetCallbackEventReference(
this,
"arg",
"FunctionCallBack",
"context",
"FunctionCallBackError",
false);
string ScriptFonctionCliente =
"function ExecuteCallBack(arg,context){" +
ReferenceVersFonctionClienteInitiatriceDuCallBack + ";}";
Page.ClientScript.RegisterClientScriptBlock(
this.GetType(),
"callback",
ScriptFonctionCliente,
true);
HtmlGenericControl h = new HtmlGenericControl();
h.TagName = "div";
h.ID = InternalId;
this.Controls.Add(h);
}
public string GetCallbackResult()
{
return "";
}
public void RaiseCallbackEvent(string eventArgument)
{
string[] tks = eventArgument.Split(';');
setNbrClickedStar(tks[0], tks[1]);
}
}
For the client side on the JavaScript starhelper.js file, you must provide these reference methods:
function FunctionCallBack(result, context)
{}
function FunctionCallBackError(result, context)
{}
function setCurrentNumber(pCurrentNumber , pIdDivContainer)
{
var str = pIdDivContainer+";"+pCurrentNumber;
ExecuteCallBack(str,'context');
}
Points of Interest
I have learned how to create an ASP.NET Web control with a complete JavaScript treatment. I discovered the fundamental differences between IE and others browsers.
Thanks
Thanks to Phillipe Pele for his JavaScript compatibility help (IE / FireFox etc...)