サーバーサイド CFML
このドキュメントでは、クライアントサイド CFML の機能について説明します。クライアントサイド CFML により、CFML を使用してクライアントサイドのアプリケーションを開発できるようになります。クライアントサイド CFML は、CF ベースのモバイルアプリケーションの開発に使用できます。このアプリケーションの CFML コードは、ColdFusion サーバーによって HTML/JavaScript に変換されます。
<cfclient> は、モバイル開発をサポートするために ColdFusion 11 で導入されたタグです。このタグは、取り囲む CFML コードを JavaScript コードに変換する目的で導入されました。ColdFusion 開発者は、CFML を使用したモバイルアプリケーションの開発を、<cfclient> タグによる変換機能を利用して実施できるようになりました。そのため、モバイル Web アプリケーションを記述するための JavaScript の知識は不要です。
履歴
ColdFusion(2018 リリース)アップデート 2:
- 次のメソッドが導入されました。ユーザーは、次のロジックを記述できます。
- mobileServer
- validationCFC
- ColdFusion Administrator には、モバイル用の新しいオプションがあります。詳しくは、モバイル設定を参照してください。
- 追加の関数およびタグをサポートします。
ヘルパー cfc もあります。これは、ColdFusion 2018 リリースのアップデート 2 で導入されました。
<cfclient> は、JavaScript と HTML を使用したモバイルアプリケーション構築に伴う複雑性を取り除くので、経験豊富な JavaScript 開発者でも、<cfclient> を使用してモバイルアプリケーション開発を簡単にすることができます。
クライアントサイドで実行される CFML コンストラクトは、<cfclient> タグの内部に埋め込む必要があります。タグ、関数および CFML 機能の一部については、HTML/JavaScript への変換がサポートされません。<cfclient> タグがサポートするすべての CFML のタグと関数については、「サポートされる CFML 言語コンストラクト」と「サポートされる CFML タグ」を参照してください。
特定のタグと関数のセットのみをサポートするように選択された背景には、クライアントサイドのモバイルアプリケーション開発への CFML の関連性を強化することがあります。
変換の仕組み
通常の <cfoutput> タグがブラウザー上でレンダリングされる仕組みについて確認していきましょう。
次のような ColdFusion コードがあるとします。
<cfoutput>Hello World</cfoutput>
ブラウザーが ColdFusion サーバーから取得する内容は次のとおりです。
Hello World
カスタムの hello world の例の節で示した Hello World の <cfclient> の例をもう一度確認してみましょう。
ここでは、次の ColdFusion コードがあるとします。
<cfset myvar = “Hello World”> <cfoutput>#myvar#</cfoutput> </cfclient>
ColdFusion サーバーによって変換される Web ページのソースを確認すると、このソースは、HTML ページにラップされた純粋な JavaScript になります。
お分かりのとおり、<cfclient> ブロック内にある CFML コードが JavaScript に変換されます。この例は単純ですが、複雑な CFML コードに対しても同様の変換が実行されます。
サポートされる CFML 言語コンストラクト
クライアントサイド CFML では、次の CFML 言語コンストラクトがサポートされます。すべての論理/条件コンストラクトおよびフローコンストラクトが含まれます。
- IF/ELSE/ELSEIF
- WHILE/DO WHILE
- CFLoop/CONTINUE/BREAK
- SWITCH/CASE/DEFAULTCASE
- TRY/CATCH/FINALLY
- FOR
- TERNARY OPERATOR
- THROW
- IMPORT
- INCLUDE
- ABORT
- EXIT
- FUNCTION/ARGUMENT/RETURN
- FUNCTION INVOCATION
- CUSTOM TAGS
サポートされる CFML タグ
クライアントサイド CFML では、次の CFML タグがサポートされます。
- cfset
- cfoutput
- cfinclude
- cfscript
- cfobject
- cfinvoke
- cfmodule
- cfsavecontent
- cfparam
- cfproperty
- cfcomponent
- cfabort
- cfexit
- cfreturn
- cfbreak
- cfcontinue
- cfquery
- cfflush
クライアントサイド CFML では、メンバー関数もサポートされます。<cfparam> タグはデバイス API をサポートしません。
ColdFusion(2018 リリース)アップデート 2 でサポートされるタグ
- cfdbinfo
- cfinsert
- cfobjectcache
- cfprocparam
- cfprocresult
- cfquery
- cfquery
- cfstoredproc
- cftransaction
- cfupdate
- cfdocument
- cfdocumentitem
- cfdocumentsection
- cflog
- cfprocessingdirective
- cfprint
- cfcollection
- cfftp
- cfindex
- cfsearch
- cfxml
- cfdirectory
- cffile
- cflocation
- cfpdf
- cfpdfform
- cfpdfformparam
- cfpdfparam
- cfpdfsubform
- cffeed
- cfimap
- cfhttp
- cfhttpparam
- cfmail
- cfmailparam
- cfmailpart
- cfpop
- cfcache
- cfcookie
- cfschedule
クライアントサイド CFML とサーバーサイド CFML の違い
<cfclient> コードブロック内ではあらゆる有効な CFML コードを記述できますが、CFML のタグとコンストラクトに対しては動作上の制約があります。動作上の制約の一部について、次に示します。
- 暗黙 的な 構造体のキーは静的なものになります。例えば、{"#a#":"value"} と宣言することはできません。また、{a:a} は {'a':a} になります。
<cfinclude> 内では、次のような動的テンプレート名(##)はサポートされません。
<cfset x=“abc.cfm”> <cfinclude template=“#x#”> </cfclient>
この制約は <cfmodule> タグにも適用されます。
- また、<cfinclude> タグは、拡張子が .cfm、.js および .css のファイルのみをサポートします。
- <cfclient> での boolean の動作は異なります。例えば、ColdFusion では、0/1、true/false、'true'/ ’false ' および yes/no はすべて boolean として扱われます。一方、<cfclient> では true/false のみが boolean です。
- ColdFusion では、x="1" は引用符があっても数値と見なされます。一方、<cfclient> ではこれは文字列として扱われます。 異常な 動作を防ぐために、関数に対しては厳密なデータ型に従ってください。
- ColdFusion では <cfset x="1a"> は日付ですが、<cfclient> 内では日付ではありません。<cfclient> は、ColdFusion の日付形式ではなく、JavaScript の日付形式に従います。
- ColdFusion では <cfset x = 1/2> は 0 ですが、<cfclient> 内部では 0.5 です。
- ColdFusion サーバーの例外はクライアントサイドでは機能しません。
createDate、createTime および createDateTime によってそれぞれ作成される Date オブジェクト、Time オブジェクトおよび DateTime オブジェクトの形式は、サーバーサイドの CFML の動作とは異なります。例えば、次のコードがあるとします。
<cfoutput>#CreateDateTime( 1776, 7, 4, 12, 59, 0)#</ cfoutput >
サーバーサイドでは、次の出力が得られます。
{ts '1776-07-04 12:59:00'}
クライアントサイド CFML で parseDateTime を使用する場合は、creatDateTime 関数から取得した出力を引数として渡し、DateTime オブジェクトを作成してください。
次のコードは、strict データ型なので機能しません。
<cfset mytimespan = #createtimespan(2, 1, 16, 30)#> <cfoutput>#date1 + mytimespan#</cfoutput> <cfoutput>#DateFormat(date1 + mytimespan)#</cfoutput>
この例では、datetime に追加する場合の timespan は文字列になります。
DateFormat 関数は、Firefox および Internet Explorer では機能しません。Chrome では、この関数は、結果を正しく表示します。考えられる対応策は、createDateTime(2003,6,11,10,50,32) のような関数を使用して、dateFormat 関数に日付オブジェクトを渡すことです。
- 関数の命名規則 – ブラウザーおよび PhoneGap によってサポートされる関数にはサーバー CFML の構文が適用されます。例えば、FileXXX となります。PhoneGap 関数は Object アクセスアプローチに従います。例えば、Camera.XXX となります。
- サーバー サイドで使用 できるスコープは、 クライアント サイドではサポートされません。
- Argument Collection は、引数を渡す目的ではサポートされません。
数値が 0002、00001、1.0E+5 などでソートタイプ が テキストの場合に、arraySort 関数の動作が異なります。
anumeric = arrayNew(1); anumeric[1] = 01; anumeric[2] = 001; anumeric[3] = 1; anumeric[4] = 1.001; anumeric[5] = 1.1; anumeric[6] = 1.101; anumeric[7] = 1.109; anumeric[8] = 1.11; anumeric[9] = 2; anumeric[10] = 02; anumeric[11] = 00002; anumeric[12] = 20; anumeric[13] = 50; anumeric[14] = 1.0E+2; anumeric[15] = 100; anumeric[16] = 1000; anumeric[17] = 1.0E+5; </cfscript> <cfset arraySort(anumeric, "text")> <cfloop array="#anumeric#" index=i> <cfoutput>#i#</cfoutput> </cfloop>
上のコードの実際の出力:
1 1 1 1.001 1.1 1.101 1.109 1.11 100 100 1000 100000 2 2 2 20 50
予想される出力:
00002 001 01 02 1 1.001 1.0E+2 1.0E+5 1.1 1.101 1.109 1.11 100 1000 2 20 50
ソートの結果が予想と異なる理由は、JavaScript では 02、002、2 の表記がどれも「2」を表すからです。
- ある構造体が内部的に別の構造体を複数回参照している場合に、その 構造体 に対する duplicate 関数の動作が異なります。 サーバー サイドでは、重複する構造体の参照キーの値を変更すると、別の参照ポイントの値も変更されます。一方、 クライアントサイド CFML では、そのような結果にはなりません。
<cfset str2 = {name: 'str2', value1: str1, value2: str1}> <cfset str2dup = duplicate(str2)>
この例で、str2dup.value1.value の値を変更すると、サーバーサイドで str2dup.value2.value の 値 も自動的に変更されます。value1 も value2 も 同じ 構造体を 参照 しているからです。一方、 クライアント サイドでは、このような動作になりません。
- クライ アント サイドでは、インクルードされた CFM または CFC からの super 関数の呼び出しはサポートされません。
- 位置関連の引数はサポートされません。
<cfclient> タグ内に <cfoutput> タグを使用する場合、<cfoutput> タグの内容はすぐには処理されません。したがって、このコードの使用中に特定の問題が発生する可能性があります。
<cfoutput> <div id="result"></div> </cfoutput> <cfset document.getElementById("result").innerHTML = "Hello"> <cfclient>
この場合、document.getElementById() ステートメントの呼び出し中に、cfoutput は処理されません。したがって、ID "result" を持つ要素は見つからず、実行時エラーが発生します。
次の場合、cfoutput を使用することなく、DOM に直接書き込みできます。
<div id="myDiv"></div> <cfclient> <cfset document.getElementById("myDiv").innerHTML += "<div id=""result""></div> <cfset document.getElementById("result")+="Hello"> </cfclient>
または、別の回避策として、<cfoutput> の後に明示的に flush を指定する方法もあります。
<cfoutput> <div id="result"></div> </cfoutput> <cfflush> <cfset document.getElementById("result").innerHTML = "Hello"> <cfclient>
このアプローチを採用する場合、cfoutput 内の HTML コンテンツが整形式であることを確認してください。
クライアントサイド CFML と JavaScript
重要:CFML の変数名と関数名では、大文字と小文字が区別されます。 |
CFML から、JavaScript を呼び出す場合:
- クライアントサイド CFML では大文字と小文字が区別されるので、CFML から CFML の関数および変数を参照するときは、 関数 名および変数名の大文字と小文字を正しく使用してください。
JavaScript から、CFML を呼び出す場合:
- クライアントサイド CFML では大文字と小文字が区別されるので、JavaScript から CFML の関数および変数を参照するときは、 関数 名および変数名の大文字と小文字を正しく使用してください。
JavaScript ファイルのロード
次の例に示すように、loadJSFile() 関数を使用して、ColdFusion コード内の JavaScript ファイルの内容をロードできます。
{ function init () { cfclient.loadJSFile("yourjsfile.js", function () { alert("Script loaded"); }); } }
JavaScript ファイルのロードにはほかにも、<cfinclude> が使用できます。
同期/非同期関数呼び出し
ColdFusion では、関数呼び出しが同期的か非同期的かが自動的に判定されます。ただし、非同期関数を同期モードで呼び出す必要がある場合は、invokeInsyncMode 関数を使用できます。必要な作業は、関数呼び出しを invokeInSyncMode 関数呼び出しで囲むことだけです。例えば、invokeInSyncMode (myAsyncFunc(arg1,arg2)) とします。InvokeCFClientFunction を参照してください。
非同期動作
ColdFusion 開発者はこれまで常に、同期プログラミングモデルを使用してきました。しかし、JavaScript を使用したクライアントアプリケーションのプログラミングでは、非同期モデルに従う必要があります。幸いにも、ColdFusion では同期から非同期への変換の大部分が自動的に実行されます。
例えば、次のようなスクリプトがあります。
<cfscript> try { //Your code that throws an exception } catch (e) { // This statement will be reached unlike // in typical asynchronous model } </cfscript>
「既知の」同期モデルを通じて <cfclient> 内で非同期関数を使用できることは、ColdFusion を使用してモバイルアプリケーションを構築する際に非常に便利です。
ColdFusion では自動的に同期コードが非同期コードに変換されるので、クライアントコードでの例外処理が容易になります。
いくつかのタグの動作が、同期動作をサポートするように変更されています。この過程で、一部のタグについては機能が異なる場合があります。例えば、<cfloop> では、<cfclient> とともに使用した場合に次の機能はサポートされません。
- COM コレクションに対するループ
- 日付または時刻の範囲に対するループ
- ディレクトリに対するループ
ヘルパー CFC
component { public boolean function isauthorized(String accesstoken) { //Write logic for accesstoken validation return true; } public boolean function validateparameters(Struct context){ writedump(var=context,output='console'); return true; } }
サーバーのヘルパー cfc をコピーします。適切な名前を付けます。 cfm で、次のようにパスを指定します。
<cfclientsettings mobileserver='http://localhost:8500' enabledeviceapi="false" validationcfc='path for cfc'>
isauthorized を使用するには、次のように、クライアントサイドのアクセストークンを設定する必要があります。
localStorage.setItem("_cf_access_token" + "app2", myToken);
このトークンは、その後、ユーザーが使用するサーバータグ用にサーバーに対しておこなわれる各リクエストと共に渡されます。
また、トークンを検証するためのロジックを validation.cfc に記述する必要があります。
ここでは、
- _cf_access_token は単なるキーワードです。
- app2 はアプリケーションの名前です。
- myToken は格納されるトークンです。このトークンは、ユーザーまたはクライアントによって生成される必要があります。ログイン用の独自のカスタム実装がある場合、ログイン後に、次に示すコードを使用してクライアントサイド(ブラウザー/モバイルアプリケーション)で設定します。
localStorage.setItem(“_cf_access_token” + appname, userToken)
- isAuthorized:アクセストークンが有効かどうかをチェックします。
- validateParameters :戻り値が false の場合、サーバーコールは実行されません。パラメーター検証に失敗したことを示すエラーを返します。
これらのメソッドは boolean(true または false のどちらか)を返します。2 つのメソッドのどちらかを使用したい場合は、使用しないほうのメソッドも記述して true を返す必要があります。
Validation CFC
component { public boolean function validateparameters(Struct context){ // context.functionname // context.line // context.file // context[0] - Data object - Requires deserialization objectData = deserializeJSON(context[0]) writeDump(var=context.functionname,output='console'); writeDump(var=serializeJSON(objectData.ROWCOUNT),output='console'); return true; } }
CFM
<cfclientsettings mobileserver='http://your-server:port-number/' enabledeviceapi="false" validationcfc="/usr/local/htdocs/validationFlow/_cfquery.cfc"> <cfclient> <cfquery name="q1" type="server" datasource = "cfartgallery"> select * from art </cfquery> <cfoutput>#serializeJSON(q1)#</cfoutput> <cfoutput>Expected: Database Data</cfoutput> </cfclient>
ColdFusion 関数のサポート
既存のデータ型と関数を使用して、ColdFusion でモバイルアプリケーションを記述し始めることができます。<cfclient> タグでは、CFML のデータ型と関数がサポートされます。
次の関数は、ColdFusion ベースのモバイルプロジェクトにおけるデータ型と関数の使用例を示しています。
CFML 単純データ型の使用
単純データ型の使用例を次に示します。
<cfclient> <cfset myVar1 = 1> <cfset myVar2 = “hello”> <cfset myVar3 = true> </cfclient>
CFML 構造体の使用
単純な構造体の使用例を次に示します。
<cfclient> <cfset myStruct = structNew()> <cfset myStruct.key1= “hello”> <cfif structKeyExists(myStruct, “key1”)> ... </cfif> </cfclient>
CFML 配列の使用
配列の使用例を次に示します。
<cfclient> <cfset myArray = arrayNew(1)> <cfset myArray[1] = “hello”> </cfclient>
CFML 関数の使用
関数の使用例を次に示します。
<cfclient> <cfif arrayLen(myArray) gt 1 > ... </cfif> <!--- using the math function---> <cfset sum = arraySum(myArray) > <!--- using the date/time function---> <cfset currentDate = now() > <!--- using the locale function---> <cfset locale = getLocale() > </cfclient>
ColdFusion(2018 リリース)アップデート 2 でサポートされるすべての関数のリスト
クライアントサイド CFML でサポートされるすべての配列関数を次に示します。
- arraySlice
- arrayAppend
- arrayIsDefined
- arrayAvg
- arrayIsEmpty
- arrayClear
- arrayLen
- arrayMax
- arrayNew
- arrayMin
- arraySort
- arrayDelete
- arrayToList
- arrayPrepend
- isArray
- arrayResize
- listToArray
- arraySet
- arrayFind
- arrayFindAll
- arraySum
- arraySwap
- arrayFindNoCase
- arrayFindAllNoCase
次の配列関数はサポートされません。
- arrayFilter(クロージャ関数)
クライアントサイド CFML でサポートされるすべての構造体関数を次に示します。
- isStruct
- structDelete
- structAppend
- structInsert
- structClear
- structIsEmpty
- structCopy
- structKeyExists
- structCount
- structNew
- structFind
- structUpdate
- structFindKey
- structFindValue
- structGet
- structKeyArray
- structKeyList
- structSort
クライアントサイド CFML でサポートされるすべてのリスト関数を次に示します。
- find
- findNoCase
- findOneOf
- formatBaseN
- lCase
- left
- len
- listAppend
- listChangeDelims
- listContains
- listContainsNoCase
- listDeleteAt
- listFind
- listFindNoCase
- listFirst
- listGetAt
- listInsertAt
- listLast
- listLen
- listPrepend
- listQualify
- listRest
- listSetAt
- listSort
- listToArray
- listValueCount
- listValueCountNoCase
- replaceList
- valueList
次のリスト関数はサポートされません。
- getClientVariablesList
次の文字列関数がサポートされます。
- binaryEncode
- binaryDecode
- charsetEncode
- charsetDecode
- toBase64
- toBinary
- toString
- uRLDecode
- uRLEncodeFormat
- LSEuroCurrencyFormat
- LSIsCurrency
- LSIsNumeric
- LSNumberFormat
- LSParseCurrency
- LSParseEuroCurrency
- LSParseNumber
次の正規表現関数がサポートされます。
- rEFind
- rEMatch
- rEFindNoCase
- rEMatchNoCase
- rEReplace
- rEReplaceNoCase
- rEEscape
次の決定関数がサポートされます。
- IIF
- INT
- IsBinary
- IsCustomFunction
- IsDDX
- IsInstanceOF
- IsJSON
- IsObject
- IsPDFArchive
- IsPDFFile
- IsPDFObject
- IsSafeHTML
- IsWDDX
次のトランザクション関数がサポートされます。
- TransactionCommit
- TransactionRollback
- TransactionSetSavePoint
次の算術関数はサポートされません。
- precisionEvaluate
次の日付関数はサポートされません。
- createODBCDate
- createODBCTime
- createODBCDateTime
- lSDateFormat
- lSIsDate
- lSParseDateTime
- lSTimeFormat
次のユーティリティ関数がサポートされます。
- isBoolean
- isDefined
- decimalFormat
- isNumeric
- dollarFormat
- isNull
- htmlCodeFormat
- isSimpleValue
- htmlEditFormat
- isValid
- numberFormat
- createUUID
次のファイル関数がサポートされます。
- DirectoryCopy
- DirectoryCreate
- DirectoryDelete
- DirectoryExists
- DirectoryList
- DirectoryRename
- GetDirectoryFromPath
- FileAppend
- FileClose
- FileCopy
- FileDelete
- FileExists
- FileGetMimeType
- FileIsEOF
- FileMove
- FileOpen
- FileRead
- FileReadBinary
- FileReadLine
- FileSeek
- FileSetAttribute
- FileSetLastModified
- FileSkipBytes
- FileUpload
- FileUploadAll
- FileWrite
- FileWriteLine
- GetFileFromPath
- GetFileInfo
- IsFileObject
次のクエリー関数が使用されます。
- QuerySort
- QueryAddRow
- QueryConvertForGrid
- QueryEach
- QueryAddColumn
- QueryReduce
- QuerySetCell
- EntityToQuery
- ORMExecuteQuery
- IsQuery
- QueryMap
- QueryNew
- QueryDeleteColumn
- QueryGetRow
- RemoveCachedQuery
- QueryGetResult
- QueryKeyExists
- QueryDeleteRow
- QueryExecute
その他のサポートされる関数:
- Max
- Min
- Minute
- NumberFormat
- PreserveSingleQuotes
- Quarter
- QuotedValueList
- Rand
- Randomize
- RandRange
- Asc
- BinaryDecode
- BinaryEncode
- BooleanFormat
- Canonicalize
- Ceiling
- CharsetDecode
- CharsetEncode
- Chr
- CreateObject
- CreateUUID
- DE
- DecodeForHTML
- DecodeFromURL
- DecrementValue
- Decrypt
- DecryptBinary
- Deserialize
- DeserializeJSON
- DollarFormat
- EncodeForCSS
- EncodeForDN
- EncodeForHTML
- EncodeForHTMLAttribute
- EncodeForJavaScript
- EncodeForLDAP
- EncodeForURL
- Encrypt
- EncryptBinary
- Evaluate
- Exp
- Find
- FindNoCase
- FindOneOf
- Fix
- Floor
- GeneratePBKDFKey
- GenerateSecretKey
- GetApplicationMetadata
- GetBaseTagData
- GetBaseTagList
- GetComponentMetadata
- GetLocale
- GetLocaleDisplayName
- GetMetadata
- GetMetricData
- GetPrinterInfo
- GetPrinterList
- GetSystemFreeMemory
- GetSystemTotalMemory
- GetTickCount
- GetTotalSpace
- Hash
- HMac
カスタムタグのサポート
既に過去数リリースの ColdFusion で、カスタムタグが使用されてきました。カスタムタグを使用すると、ColdFusion に付属するタグに独自のタグを追加して、CFML を拡張できます。このリリースでは、カスタムタグを <cfclient> 内でも作成できるようになりました。これ以降の節では、カスタムタグを使用してモバイルアプリケーションを構築する際のサポートされる機能と制限事項に関する概要を説明します。
カスタムタグでは、アプリケーションとサーバーのマッピングもサポートされます。
カスタムタグのパス
カスタムタグは、次の場所にある場合に検出されます。
- 呼び出し元のページと同じディレクトリにあるカスタムタグ
- cfusion /CustomTags ディレクトリにあるカスタムタグ
- cfusion /CustomTags ディレクトリのサブディレクトリにあるカスタムタグ
- サーバーとアプリケーションのマッピング用フォルダーにあるカスタムタグ
カスタムタグの呼び出し
カスタムタグは次の方法で呼び出すことができます。
- cf_<tagname> を使用します。例えば、<cf_mytag> と呼び出します。
- <cfmodule> タグを使用します。例えば、<cfmodule template="../cf_mytag.cfm"> と記述します。
- また、<cfmodule name="tags.mytag"> とも記述できます。
- <cfimport> タグについては、taglib を使用してカスタムタグをインポートします。
- 例えば、<cfimport prefix = “myTags” taglib = “/custom”> と記述します。
- ドット(.)記法を使用して、サブディレクトリ内にあるカスタムタグにアクセスできます。例えば、<cfmodule name = "tags.mytag"> を使用します。
<cfimport> では、カスタムタグへのパスのみがサポートされるので、JSP タグライブラリを使用することはできません。
値の受け渡し
名前と値のペアを使用して、カスタムタグに値を渡すことができます。
<cf_mytag myname=#myvalue#>
また、複数の名前と値のペアをカスタムタグに渡すこともできます。
<cf_mytag myname1=#myvalue1# myname2=#myvalue2#>
カスタムタグに渡された引数にアクセスするために、次のようにカスタムタグの CFM ファイルで attributes スコープを使用できます。
#attributes.myname1# and #attributes.myname2#
呼び出し元のページにデータを送信し返すために、次のようにカスタムタグの CFM ファイルで caller スコープを使用できます。
<cfset caller.myname=#attributes.myname1# & " " & #attributes.myname2#>
カスタムタグに構造体を渡すこともできます。
<cfset args=structNew()> <cfset args.x = "‐X‐"> <cfset args.y = "‐Y‐"> <cf_mytag arg1="value1" attributeCollection=#args# anotherarg="16">
タグインスタンスのデータ
カスタムタグページの実行時には、タグインスタンスに関するデータが thisTag 構造体に保持されます。カスタムタグから thisTag 構造体にアクセスして、タグの処理を制御できます。
終了タグが指定されているかを判定するには、次のように hasEndTag を使用します。
<cfif thisTag.hasEndTag is 'false'> <!‐‐‐ Abort the tag‐‐‐> <cfabort /> </cfif>
タグの実行モードを判定するには、executionMode 属性を使用します。次の 3 つのモードがサポートされます。
- Start モード – 開始タグを処理するモード
- End モード – 終了タグを処理するモード
- Inactive モード – ネストされたタグを使用してカスタムタグを処理するモード
<cfif thisTag.executionMode is 'start'> <!‐‐‐ Process start tag ‐‐‐> <cfelseif thisTag.executionMode is 'end'> <!‐‐‐ Process end tag ‐‐‐> </cfif>
thisTag.GeneratedContent 変数を使用すれば、カスタムタグの本文テキストにアクセスできます。このテキストはタグの処理時に変更できます。thisTag.generatedContent 変数の内容は、タグの出力の一部としてブラウザーに返されます。この内容には、本文のすべてのテキストおよび HTML コード、ColdFusion の変数、式および関数の評価結果、さらに子孫タグによって生成された結果が含まれます。
次の例を参照してください。
<cfif thisTag.executionMode is 'end'> <cfset thisTag.generatedContent ='<!‐‐#thisTag.generatedContent#‐‐>'> </cfif>
ネストされたサブタグでは、属性を親タグに渡すことができます。サブタグでは、cfassociate を使用して、属性をベースタグまたは祖先タグに渡すことができます。
<cfassociate baseTag="tagName" dataCollection="collectionName">
ベースタグからサブタグの属性にアクセスする方法について、次のコードに示します。
<cfparam Name='thisTag.assocAttribs' default=#arrayNew(1)#>
また、次のように getBaseTagList() ヘルパーメソッドを使用して、サブタグから祖先のデータにアクセスすることもできます。
<cfset ancestorlist = getBaseTagList()>
getBaseTagList() メソッドは、大文字の祖先タグ名をカンマで区切ったリストを文字列として返します。また、getBaseTagData() メソッドを使用して、n 番目の祖先の属性をすべて含むオブジェクトを返すこともできます。
カスタムタグの処理のアボート
<cfexit> タグまたは <cfabort> タグは、ページの実行を終了します。
カスタムタグの差異に関するリスト
カスタムタグの 動作 における既知の問題や差異について、次に示します。
- <cfclient> では variables スコープがサポートされます。ただし、明示的にスコープを指定する必要があります。
|
クライアントサイド CFML |
---|---|
caller.cfm
customtag.cfm
<cf_customtag value1="old_value"> <cfset caller[attributes.value1]="new_value"/> |
caller.cfm
customtag.cfm
<cfclient> <cfset caller[attributes.value1]="new_value"/> |
- 非同期呼び出しの後でカスタムタグ内で "#attributes.attributename#" 構文を使用している場合、予期しない動作となります。
サーバーサイド CFML |
クライアントサイド CFML |
---|---|
<>cfset divid = "#attributes.div_id#" |
このコードは機能しません。
<cfset divid = "#attributes.div_id#"> <cfset divid = #attributes.div_id#>
|
呼び出し元の属性に渡された数値は、カスタムタグには文字列として渡されます。
<cf_custom attr1="1">
この例では、算術演算内で attr1 属性にアクセスしている場合、attr1 は数値に変換されます。一方、クライアントサイドのカスタムタグでは、このように機能しません。次のコードを使用する必要があります。
<cf_custom attr1=1>
または
<cfset x = 1> <cf_custom attr1=#x#>
クライアントのカスタムタグでは、型変換は処理されません。
- Function 呼び出し元の CFM で宣言された関数には、サーバーサイドでは caller.functionname() を使用してカスタムタグ(CFM)内でアクセスできます。一方、クライアントサイドではこのような動作になりません。
サーバーサイド CFML |
クライアントサイド CFML |
---|---|
<cffunction name="func1"> <cfretrurn "Hello"> </cffunction> <cf_custom> <cfset caller.func1()>
|
|
- インクルードされたファイルのパスを渡すための変数の使用は、<cfclient> 内では機能しません。
サーバーサイド CFML |
クライアントサイド CFML |
---|---|
<cfset path="someCFM.cfm"> <cfinclude template=#path#> |
これはサポートされません。 |
- <cfmodule> を使用して template 属性または name 属性を渡す操作は、<cfclient> では機能しません。
サーバーサイド CFML |
クライアントサイド CFML |
---|---|
<cfset path="someCFM.cfm"> <cfmodule template=#path#> |
|
- カスタムタグテンプレートでスローされた例外は、呼び出し元の CFM で定義された例外ハンドラーによって処理されません。クライアントサイド CFML でカスタムタグ名が誤っているか、インクルードされた CFM 名が誤っている場合、コンパイル時に例外が発生します。
JavaScript ファイルの場所(<cfinclude> タグで指定するか <script> タグを使用)によって、ステートメントの実行順が異なります。
<cfclient> 以外のカスタムタグを <cfclient> の呼び出し元の CFM から呼び出すことはできません。また、クライアントサイドカスタムタグは、<cfclient> タグの外部にサーバーサイド ColdFusion タグを持つことはできません。これは、クライアントサイドに含まれている CFM にも当てはまります。より効果的にデバッグを行うために、スクリプトブロック、リンクタグ、およびスタイルタグをクライアントサイドカスタムタグに追加しないでください。必ず、別途 JavaScript ファイルまたは CSS ファイルを作成し、作成したファイルを <cfinclude> タグを使って追加してください。
<cfinclude template="utils.js"> or <cfinclude template="new.css">
これは、クライアントサイドに含まれている CFM にも当てはまります。
CFC のサポート(クライアントサイドおよびサーバーサイド)
クライアントサイド CFC は、cfclient コンポーネントの client=true 属性を使用して記述できます。例えば、client=true を他のコンポーネント属性とともに使用して、クライアントサイド CFC であることを識別できます。次の例を参照してください。
component client=true { public function foo() { //some code here } }
<cfclient> が ColdFusion サーバーと非常にシームレスに通信するので、開発者は ColdFusion サーバープログラミングと同じようにサーバーコンポーネントのオブジェクトを作成し、そのオブジェクトの関数を呼び出すことができます。ColdFusion サーバーは、言語に対して制約を課すことなく、モバイルクライアントとサーバー間に必要となる各種相互作用のすべてを容易にします。
次の例を参照してください。
<cfclient> <!-- Create a JS proxy of server side component myCFC.cfc‐‐‐> <cfset proxy = new app1.controls.myCFC(id)> <!-- Update some data ‐‐‐> <cfset proxy.setVar("myVar1")> <cfset proxy.setProperties(someStructVar)> </cfclient>
この例では、<cfclient> タグ内でリモート CFC の関数を呼び出しています。新しい演算子によって、サーバー CFC へのプロキシが作成されます。インスタンス化された CFC オブジェクトを使用して、その CFC のリモート関数を呼び出すことができます。
サーバー CFC は、client 属性が true に設定される点を除いて、他の CFC と同様です。
<cfclient> タグでは、その他の CFML コンストラクトと同様に CFC を使用できます。<cfclient> ブロック内で CFC を使用する方法は複数あります。
簡単な使用例を次に示します。
<cfclient> <cfset obj = new mycfc()> <cfset obj1 = createObject(“component”,”mycfc”)> </cfclient>
この例では、mycfc.cfc はクライアントサイド CFC でもサーバーサイド CFC でもかまいません。お分かりのとおり、CFC は createObject、new キーワードおよび cfinvoke の機能を使用して作成できます。
また、別の CFC から機能を拡張した CFC を使用することもできます。
<cfclient> <cfset obj = new mycfc()> <!--- mycfc extends mycfc1.cfc present in the same directory ---> <cfset result = obj.getResult() > <!--- getResult() function present in mycfc1.cfc and can be accessed from the extending classes ---> </cfclient>
mycfc.cfc がクライアントサイド CFC の場合は、mycfc1.CFC もクライアントサイド CFC である必要があります。このことは、mycfc.cfc がサーバーサイド CFC の場合のサーバーサイド CFC にも適用されます。
また、マップされたパスをインポートするために、<cfimport> を使用することもできます。
<cfimport path=“com.*” /> <cfset obj = new com.mycfc() /> <!--- mycfc present in directory mapped to com ---> You can also use functions within a CFC: <cfclient> <cfset obj = new mycfc() > <cfset obj.foo() > <!--- invoke function on cfc instance ---> </cfclient>
mycfc.cfc がサーバーサイド CFC の場合、foo() 関数はリモート関数になります。
データベースクエリーのサポート
現在サーバーサイド CFML コードで使用しているのと同じように、クライアントサイド CFML で <cfquery> タグを使用し始めることができます。このリリースでは一部の <cfquery> 機能はサポートされないことに注意してください。クライアントサイド CFML でのデータベースクエリーのサポートは、Web Database(Web SQL)に基づいています。そのため、この機能は特定のブラウザー上で動作しない可能性があります。お使いのブラウザーが Web SQL をサポートしているかを確認するには、この Web ページを参照してください。
サポートされる機能
クライアントサイド CFML で利用できる <cfquery> サポートの範囲を次に示します。
- <cfquery> タグは、次の属性のみをサポートします。
- name = "query name"
- dataSource = "data source name"
- result = "resultVar"
結果の変数には、sql、recordCount、columnList および sqlparameters が含まれます。
- <cfloop> タグを使用してクエリーに対する繰り返し処理を実行できます。<cfloop> タグがサポートする属性は、query、 startrow および endrow です。
- <cfqueryparams> タグを使用して、クエリーをパラメーター化して実行できます。
- <cfqueryparam> タグでは、value 属性のみがサポートされます。
- queryparam 属性の値は、queryExecute 関数を使用し、配列内の位置を示すパラメーターを通じて指定できます。
queryexecute (" sql ", queryparams , queryoptionsmap )
- クライアントからサーバーおよびサーバーから クライアント へのクエリーのシリアライズおよびデシリアライズは、シームレスに実行されます。
- クライアントサイド CFML の isQuery 関数を使用して、変数がクエリー型であるかをチェックできます。
サポートされない機能
次の機能はサポートされません。
- クエリーに対するクエリーの実行
- QueryNew、QueryAddRow などのインメモリのクエリー作成関数
使用例
クライアントサイド CFML の <cfquery> タグの基本的な使用例を次に示します。
<div id="actual_1" class="async_actual"> <cfclient> <cfquery datasource="cfds" >drop table if exists birthDates</cfquery> <cfquery datasource="cfds" > CREATE TABLE if not exists birthDates( serialNo INTEGER PRIMARY KEY AUTOINCREMENT, firstname VARCHAR(20), lastname VARCHAR(20), dob TEXT) </cfquery> <!---Insert string. ---> <cfquery datasource="cfds" name="q1"> INSERT INTO birthDates(firstName, lastname,dob) VALUES('Jon', 'Doe', 'Mark') </cfquery> <cfset d1=createDate(1975, 12, 25)> <cfset a=dateFormat(d1,"yyyy-mm-dd")> <cfquery datasource="cfds" name="q2"> INSERT INTO birthDates(firstName, lastname, dob) VALUES('Jon', 'Doe', '#a#') </cfquery> <cfset d2=createDate(1980, 01, 01)> <cfset b=dateFormat(d2, "yyyy-mm-dd")> <cfquery datasource="cfds" name="q2"> INSERT INTO birthDates(firstName, lastname, dob) VALUES('Jon', 'Doe','#b#') </cfquery> <cfset d3=createDate(1985, 12, 27)> <cfset c=dateFormat(d3, "yyyy-mm-dd")> <cfquery datasource="cfds" name="q3"> INSERT INTO birthDates(firstName, lastname, dob) VALUES('Jon', 'Doe','#c#') </cfquery> <cfset startRow="2"> <cfset endRow="4"> <cfquery datasource="cfds" name="q4" result="test"> SELECT * FROM birthDates where serialNo between <cfqueryparam value="#startRow#"> and <cfqueryparam value="#endRow#"> </cfquery> <cfset write_to_div("actual_1", test.sql & "<br>" & test.recordCount & "<br>" & test.columnList)> <cfloop query="q4"> <cfset write_to_div("actual_1", firstname & " " & lastname & ":" & dob &"<br>")> </cfloop> </cfclient> <script type="text/javascript"> function write_to_div(div_id,data_to_write) { document.getElementById(div_id).innerHTML+=data_to_write; } </script> </div>
サーバーサイド <cfquery> のサポートを参照してください。