If Not IsNull in ASP Classic - vbscript

I'm fairly new to asp and I've got a syntax error I would like help on if you can.
I've got an ASP page that shows a table that pulls data from sql. Most of the data hasn't been populated yet so returns a NULL. The data type in question is numeric. I need to FormatNumber the rs when it is not null and not populate if it is.
This is what I have
<%=If Not IsNull(rs("ContractValue")) Then FormatNumber(rs("ContractValue"),0) end if%>
But as mentioned, im getting a syntax error.
What am i doing wrong?

I would recommend not using IsNull() in this scenario, but to answer the question about the syntax error first.
The reason is the <%= %> syntax which is shorthand for
<% Response.Write %>
in Classic ASP.
So what you are actually doing if written without the shorthand approach is;
<% Response.Write If Not IsNull(rs("ContractValue")) Then FormatNumber(rs("ContractValue"),0) End If %>
which is incorrect syntax and will trigger a Syntax Error.
To fix the code remove the = from the <% %> tags, like so;
<% If Not IsNull(rs("ContractValue")) Then Response.Write FormatNumber(rs("ContractValue"),0) End If %>
What about using IsNull?
While this can work it can often give weird results because a DBNull (depending on the database being used) can be different and is often different to the VBScript vbNull variant.
Because of this and the fact VBScript isn't strongly typed I find it useful to use a simple quick cast to string to avoid Nulls then check for valid data.
Example numeric check
Dim contractValue
contractValue = rs("ContractValue") & ""
If Len(contractValue) > 0 And IsNumeric(contractValue) Then contractValue = Clng(contractValue) Else contractValue = 0
You can take this further by writing a reusable piece of code that IIf() function explained in this post.
How to do a single line If statement in VBScript for Classic-ASP? (Mentioned by #TasosK in the comments)
Something like this;
Dim contractValue
contractValue = rs("ContractValue") & ""
contractValue = IIf(Len(contractValue) > 0 And IsNumeric(contractValue), contractValue, 0)
#Paul made a good point about evaluation of parameters, in the original code would potentially break
contractValue = IIf(Len(contractValue) > 0 And IsNumeric(contractValue), Clng(contractValue), 0)
because Clng(contractValue) would be evaluated regardless of whether the outcome was True or False. So any formatting would need to be afterwards or a more complex version of the IIf() function be built.

If Not IsNull(rs("ContractValue")) Then
<%=FormatNumber(rs("ContractValue"),0)%>
end if
Do not be in a hurry with Classic ASP.
I'm sure you want to insert content in between some HTML code which made you bunch up all that code. If that is the case, I suggest you separate VBscript code from HTML like below for example;
<%
Dim valueToOutput
If Not IsNull(rs("ContractValue")) Then
valueToOutput=FormatNumber(rs("ContractValue"),0)
end if
%>
<!-- HTML Code continues below with an inserted VBscript variable -->
There are a total of <%=valueToOutput%> oranges available!

If dealing with too many null fields, the code will be riddled with too many IF-THEN-ELSE statements and that would look really ugly.
Consider using the COALESCE function on the database side, so the field values don't come up as null on the recordset, or alternatively, consider using your own coalesce function in ASP that you can use over and over again.
Function Coalesce(inputValue, replaceWith)
if isnull(X) then
Coalesce = replaceWith
else
Coalesce = inputValue
end if
End Function
Then you can use something like this:
<%=FormatNumber(Coalesce(rs("ContractValue"),0),0)%>

Related

Populating VBscript array with modern array

Arrays tend to look like this in languages such as JavaScript and Python:
['Foo', 'Bar']
But in classic ASP they look like this:
Array("foo", "bar")
Is there an easy way to store a modern array in a VBScript array?
As an example of the problem this will give a type mismatch:
Dim arrayString
arrayString = "['Foo', 'Bar']"
Dim myArray()
myArray = array(arrayString)
If someone has built a library to do this conversion that would be most helpful, otherwise I'm guessing we need to do something cumbersome with split?
Are you aware that ASP classic also supports JScript (ECMAScript Version 3)? For instance, we can put function wrappers on JSON parsing and stringify functions and JScript arrays as follows:
<%# Language= "Javascript" %>
<%
//json2-min.js
if(typeof JSON!=="object"){JSON={}}(function(){"use strict";function f(e){return e<10?"0"+e:e}function quote(e){escapable.lastIndex=0;return escapable.test(e)?'"'+e.replace(escapable,function(e){var t=meta[e];return typeof t==="string"?t:"\\u"+("0000"+e.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+e+'"'}function str(e,t){var n,r,i,s,o=gap,u,a=t[e];if(a&&typeof a==="object"&&typeof a.toJSON==="function"){a=a.toJSON(e)}if(typeof rep==="function"){a=rep.call(t,e,a)}switch(typeof a){case"string":return quote(a);case"number":return isFinite(a)?String(a):"null";case"boolean":case"null":return String(a);case"object":if(!a){return"null"}gap+=indent;u=[];if(Object.prototype.toString.apply(a)==="[object Array]"){s=a.length;for(n=0;n<s;n+=1){u[n]=str(n,a)||"null"}i=u.length===0?"[]":gap?"[\n"+gap+u.join(",\n"+gap)+"\n"+o+"]":"["+u.join(",")+"]";gap=o;return i}if(rep&&typeof rep==="object"){s=rep.length;for(n=0;n<s;n+=1){if(typeof rep[n]==="string"){r=rep[n];i=str(r,a);if(i){u.push(quote(r)+(gap?": ":":")+i)}}}}else{for(r in a){if(Object.prototype.hasOwnProperty.call(a,r)){i=str(r,a);if(i){u.push(quote(r)+(gap?": ":":")+i)}}}}i=u.length===0?"{}":gap?"{\n"+gap+u.join(",\n"+gap)+"\n"+o+"}":"{"+u.join(",")+"}";gap=o;return i}}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()}}var cx,escapable,gap,indent,meta,rep;if(typeof JSON.stringify!=="function"){escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;meta={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"};JSON.stringify=function(e,t,n){var r;gap="";indent="";if(typeof n==="number"){for(r=0;r<n;r+=1){indent+=" "}}else if(typeof n==="string"){indent=n}rep=t;if(t&&typeof t!=="function"&&(typeof t!=="object"||typeof t.length!=="number")){throw new Error("JSON.stringify")}return str("",{"":e})}}if(typeof JSON.parse!=="function"){cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;JSON.parse=function(text,reviver){function walk(e,t){var n,r,i=e[t];if(i&&typeof i==="object"){for(n in i){if(Object.prototype.hasOwnProperty.call(i,n)){r=walk(i,n);if(r!==undefined){i[n]=r}else{delete i[n]}}}}return reviver.call(e,t,i)}var j;text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(e){return"\\u"+("0000"+e.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"#").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}})()
function jsonParse(str) { return JSON.parse(str); }
function jsonStringify(obj) { return JSON.stringify(obj); }
function jsArray() { return []; }
function jsArrayPush(a,v) { a.push(v); }
%>
Then, in your VBScript code you can make use of the JScript array, e.g.
<%# Language= "VBscript" %>
<%
Dim arr, str
str = "[""Foo"", ""Bar""]"
Set arr = jsonParse(str)
Call jsArrayPush(arr, "Hello")
Call jsArrayPush(arr, "World")
str = jsonStringify(arr) ' ["Foo","Bar","Hello","World"]
%>
You're comparing two different things. Your example of a "modern array" is what is called literal syntax. This tells the processor to create an array using the data and structure provided. The indexing order is typically preserved in these languages.
Your classic examples using Array() are array generating functions. They create arrays in memory with provided values, but don't necessarily imply any sort of structure at all. Many languages specifically indicate that value indexing can vary. Some languages process arrays internally as objects and often require the new keyword in addition to the array function. When this happens it's often referred to as constructor syntax.
Many languages offer one, two, or even all three ways of creating arrays.
VBScript does not offer any variation of the literal syntax.

Classic ASP: Session values fail to pass over to popup window

I'm trying to pass values through session from one page to a popup window. But it fail to pass the value. I checked the ISS where Enable Session State is true. I will post the code which I'm working please let me know something I'm missing in it or any other variable settings problem like php.ini
<script language="javascript" type="text/javascript">
function veh(url) {
popupWindow = window.open(url, 'popUpWindow', 'height=300,width=300,left=50,top=10,resizable=yes,scrollbars=yes,toolbar=yes,menubar=no,location=no,directories=no, status=yes');
}
</script>
<%
' Define to hold temporary super session
Dim strManu // Manufacture type
strManu = Session("Manu")
Dim objRS
Dim strSQL
Dim strVeh
Set objRS=Server.CreateObject ("ADODB.Recordset")
strSQL="SELECT vl.* FROM veh_tbl vl where vl.manuID= " & strManu
objRS.Open strSQL,objconn
if not objRS.eof then
strVeh=objRS("veh")
Session("Veh")=strVeh
end if
objRS.Close
Set objRS=Nothing
<a href='http://www.example.com/popup.asp' target='_self'
onclick='veh(this.href);return false'><img border='0'src='images/info.jpg'></a>
Popup window
<%
Dim strVal
strVal = Session("Veh")
%>
<FORM name=MyForm>
<% Response.Write "<label class = 'col-sm-4 col-form-label'>" & strVal & "</label>" %>
</FORM>
%>
I'm getting the value from the DB and I'm able to print the string(strVeh) in the same page. I'm not able to pass the same in pop window. It fails to show any error. Anyone please help me to address the issue.
Things I would check:
First, in href='http://www.example.com/popup.asp' does the domain and subdomain match the source page exactly? For example adding or removing the "www" may make a difference.
Are you positive if not objRS.eof then is resolving true? For example try just putting session("test") = "test" somewhere on the page outside of a conditional statement and see if that variable is available in the popup.
Had this issue recently, if I typed in 'https://www.myweb.com/checksession.asp' it would not load/could not see the session variables.
Type in 'https://myweb.com/checksession.asp' (i.e. remove the www.) and it works fine.
So something to bear in mind if referencing from another page/ajax/loading scripts etc.

Classic ASP Type Mismatch with If Then Statement

Can someone please tell me why this is tossing a Type Mismatch using Classic ASP error?
If (strPaidByPO = True) OR (arrResult(0) = "1") Then
'Do Stuff
Else
'Do Other stuff
End if
arrResults is an Array and strPaidByPO is a variable.
Thanks,
Before the If statement type the following (I think you may be making assumptions about the Types).
Call Response.Write(TypeName(strPaidByPO) & "<br />")
Call Response.Write(TypeName(arrResult) & "<br />")
Call Response.Flush()
If your variables are of the type you expected you should get the following output
Boolean
Variant()
Also you might receive this if your Array is multidimensional in which case you need to specify all the dimensions.
The other possibility is arrResult(0) contains something other than a String. In which case use TypeName(arrResult(0)) to check what that is.
Try this and see result based on which you can correct your script:
response.write(cStr(strPaidByPO) & "- My strPaidByPO value<br>")
response.write(arrResult(0) & "- My Array value")
If (strPaidByPO = True) OR (cStr(arrResult(0)) = "1") Then
'Do Stuff
Else
'Do Other stuff
End if
but if your strPaidByPO contain values other then true - false (Boolean) you need to review your approach to this completely. For example if strPaidByPO is NULL or empty your script will trough you an error like you described.

Is Nothing comparison gives type mismatch

I am trying to check if the 'Listivew.Tag property is nothing'.
I used to do the 'Is Nothing' check universally for all scenarios as first check to avoid errors
Can someone explain how to do it in VB 6?
If Not .lvwLocation.Tag Is Nothing Then
'COMPANY
str = str & IIf(Len(.lvwLocation.Tag) > 0, " and u.location_id in " & .lvwLocation.Tag, "")
End If
Gives error 'type-mismatch'
Nothing is a valid value for Object variables, and Is is the way to compare object pointers.
But a VB6 control's Tag property is a String, and VB6's String type is not an Object; it's a primitive type. That means a String variable can't be assigned Nothing -- its emptiest possible value is the empty string. (And an Object variable can't be assigned a String value.) For strings just use the same equality/inequality/comparision operators that you use for other primitive (numeric/boolean/date) types:
If .lvwLocation.Tag <> "" Then ...
In VB6 it appears that using Is Nothing to compare Objects works, Every other data type that I tried did not. In .Net Nothing represents the default value of any data type and will work like you expect.
Dim test as Object
If Not test Is Nothing Then
/////
End If
Since it appears the data type of th Tag property in VB6 is a string. I would use something like:
If .lvwLocation.Tag <> "" Then
/////
End If

Sorting a collection in classic ASP

It's quite a simple question - how do I sort a collection?
I've got a CSV file with rows in a random order. I'd like to sort the rows according to the date in one column. Do I add the rows to a recordset? Can I sort with a Scripting.Dictionary?
I've clearly been spoilt with .NET and Linq, and now I find myself back in the land of classic asp, realising I must have known this 7 years ago, and missing generics immensely. I feel like a complete n00b.
In this case I would get help from big brother .net. It's possible to use System.Collections.Sortedlist within your ASP app and get your key value pairs sorted.
set list = server.createObject("System.Collections.Sortedlist")
with list
.add "something", "YY"
.add "something else", "XX"
end with
for i = 0 to list.count - 1
response.write(list.getKey(i) & " = " & list.getByIndex(i))
next
Btw if the following .net classes are available too:
System.Collections.Queue
System.Collections.Stack
System.Collections.ArrayList
System.Collections.SortedList
System.Collections.Hashtable
System.IO.StringWriter
System.IO.MemoryStream;
Also see: Marvels of COM .NET interop
I'd go with the RecordSet approach. Use the Text Driver. You'll need to change the directory in the connection string and the filename in the select statement. the Extended Property "HDR=Yes" specifies that there's a header row in the CSV which I suggest as it will make writing the psuedo SQL easier.
<%
Dim strConnection, conn, rs, strSQL
strConnection = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\inetpub\wwwroot\;Extended Properties='text;HDR=Yes;FMT=Delimited';"
Set conn = Server.CreateObject("ADODB.Connection")
conn.Open strConnection
Set rs = Server.CreateObject("ADODB.recordset")
strSQL = "SELECT * FROM test.csv order by date desc"
rs.open strSQL, conn, 3,3
WHILE NOT rs.EOF
Response.Write(rs("date") & "<br/>")
rs.MoveNext
WEND
rs.Close
Set rs = Nothing
conn.Close
Set conn = Nothing
%>
It's been a long time for me too. IIRC you don't have an option out of the box.
If I were you I'd put all the data in an array and then sort the array. I found a QuickSort implementation here: https://web.archive.org/web/20210125130007/http://www.4guysfromrolla.com/webtech/012799-3.shtml
Also look at the "Bubble Sort", works excellent with those classic asp tag cloud.
https://web.archive.org/web/20180927040044/http://www.4guysfromrolla.com:80/webtech/011001-1.shtml
A late late answer to this, but still of value.
I was working with small collections so could afford the approach where I inserted the item in the correct place on each occasion, effectively reconstructing the collection on each addition.
The VBScript class is as follows:
'Simple collection manager class.
'Performs the opration of adding/setting a collection item.
'Encapulated off here in order to delegate responsibility away from the collection class.
Class clsCollectionManager
Public Sub PopulateCollectionItem(collection, strKey, Value)
If collection.Exists(strKey) Then
If (VarType(Value) = vbObject) Then
Set collection.Item(strKey) = Value
Else
collection.Item(strKey) = Value
End If
Else
Call collection.Add(strKey, Value)
End If
End Sub
'take a collection and a new element as input parameters, an spit out a brand new collection
'with the new item iserted into the correct location by order
'This works on the assumption that the collection it is receiving is already ordered
'(which it should be if we always use this method to populate the item)
'This mutates the passed collection, so we highlight this by marking it as byref
'(this is not strictly necessary as objects are passed by reference anyway)
Public Sub AddCollectionItemInOrder(byref existingCollection, strNewKey, Value)
Dim orderedCollection: Set orderedCollection = Server.CreateObject("Scripting.Dictionary")
Dim strExistingKey
'If there is something already in our recordset then we need to add it in order.
'There is no sorting available for a collection (or an array) in VBScript. Therefore we have to do it ourself.
'First, iterate over eveything in our current collection. We have to assume that it is itself sorted.
For Each strExistingKey In existingCollection
'if the new item doesn't exist AND it occurs after the current item, then add the new item in now
'(before adding in the current item.)
If (Not orderedCollection.Exists(strNewKey)) And (strExistingKey > strNewKey) Then
Call PopulateCollectionItem(orderedCollection, strNewKey, Value)
End If
Call PopulateCollectionItem(orderedCollection, strExistingKey, existingCollection.item(strExistingKey))
Next
'Finally check to see if it still doesn't exist.
'It won't if the last place for it is at the very end, or the original collection was empty
If (Not orderedCollection.Exists(strNewKey)) Then
Call PopulateCollectionItem(orderedCollection, strNewKey, Value)
End If
Set existingCollection = orderedCollection
End Sub
End Class

Resources