I've spent some time using Railo Coldfusion and recently purchased a home. I haven't had much time to write so I am catching up now.
I got a message that Railo is finally going to support annotations. Why is this a good thing? Because I can now use ColdMVC.
Showing posts with label ColdMVC. Show all posts
Showing posts with label ColdMVC. Show all posts
Thursday, December 22, 2011
Wednesday, April 20, 2011
ColdMVC: Quick start now available
After a long wait, ColdMVC finally has a quick start guide. Check it out here: http://www.coldmvc.com/quickstart.
Monday, March 28, 2011
ColdMVC: get an object's parents
Awhile back I posted on flattening an array of objects with Parent-Child relationship (link) and have been using it alot. But one issue I had with it was when I was looping through the array of objects I didn't know who my parents were for the current object I was working with. I already knew how deep thanks to the treeDepth property. I made this function to recursively go up the tree of objects and bring back an array of parent objects for an object.
<cffunction name="getObjectsParents" access="public" output="false" returntype="array">
<cfargument name="object" required="true"/>
<cfargument name="result" required="false" default="#[]#"/>
<cfif isObject(arguments.object.parent())>
<cfset arrayPrepend(arguments.result,arguments.object.parent())/>
<cfreturn getObjectsParents(arguments.object.parent(),arguments.result)/>
<cfelse>
<cfreturn arguments.result/>
</cfif>
</cffunction>
Thursday, February 3, 2011
ColdMVC: Number Tag
I've playing around with mobile web apps lately. ColdMVC has been a big help in getting them done quickly and "in the cloud".
I've been looking for a house since the market is so good right now and one thing I noticed when searching for houses online is the when you type in a price range only the keypad shows up on my phone. No letters. Just numbers. It's really nice. I viewed the source when I got back to my laptop and found out they were doing it with <input type="number" >. I decided to hack a ColdMVC tag together to hanlde this.
Here is how you call the tag...
Here is my hacked in logic...
The above logic doesn't supporting binding, but it works to use. It would be cool if this tag was managed my ColdMVC HTMLHelper.cfc then I would have to worry about the attributes.
I've been looking for a house since the market is so good right now and one thing I noticed when searching for houses online is the when you type in a price range only the keypad shows up on my phone. No letters. Just numbers. It's really nice. I viewed the source when I got back to my laptop and found out they were doing it with <input type="number" >. I decided to hack a ColdMVC tag together to hanlde this.
Here is how you call the tag...
<c:number name="miles" value="#service.miles()#">
Here is my hacked in logic...
<cfparam name="attributes.class" default="input"/>
<cfparam name="attributes.value" default=""/>
<cfif thisTag.executionMode eq "end">
<cfoutput>
<cfsavecontent variable="attributes.field">
<input type="number" name="#attributes.name#" title="#attributes.name#" value="#attributes.value#" class="#attributes.class#"/>
</cfsavecontent>
</cfoutput>
<cfset thisTag.generatedContent = coldmvc.form.field(argumentCollection=attributes) />
</cfif>
The above logic doesn't supporting binding, but it works to use. It would be cool if this tag was managed my ColdMVC HTMLHelper.cfc then I would have to worry about the attributes.
Wednesday, February 2, 2011
ColdMVC: Binding
I really like the binding option in the form tag of ColdMVC. It takes an object from the param scope, prefixes all the elements within it, with model's name (ex. user.first_name), and sets the value from the object. It's very handy. Here is an example of what it currently does:
If you wanted to bind the form to 2 or more objects it would be cool if you could use a bind tag and group a set of elements within a form.
Or even better on the tag itself. (I think this available already, but I am not sure).
<c:form controller="user" action="save" bind="user">
<c:hidden name="id"/>
<c:input name="first_name"/>
<c:input name="last_name"/>
<c:buttons>
<c:submit label="save"/>
</c:buttons>
</c:form>
If you wanted to bind the form to 2 or more objects it would be cool if you could use a bind tag and group a set of elements within a form.
<c:form controller="student" action="save">
<c:bind key="user">
<c:hidden name="id"/>
<c:input name="first_name"/>
<c:input name="last_name"/>
</c:bind>
<c:bind key="student">
<c:input name="student_number"/>
</c:bind>
<c:buttons>
<c:submit label="save"/>
</c:buttons>
</c:form>
Or even better on the tag itself. (I think this available already, but I am not sure).
<c:form controller="student" action="save">
<c:hidden name="id" bind="user"/>
<c:input name="first_name" bind="user"/>
<c:input name="last_name" bind="user"/>
<c:input name="student_number" bind="student"/>
<c:buttons>
<c:submit label="save"/>
</c:buttons>
</c:form>
Thursday, December 30, 2010
ColdMVC: AJAX call
Trying to make ajax calls with ColdMVC was a little difficult for me because I struggle with routes, but I found a way. Here is what I did to make an AJAX call with ColdMVC.
First I created a function on a Controller so I can return "hi" back from the AJAX call. Notice I have @view json.cfm above the function. Since ColdMVC uses routes I need to send the data to a view and cfoutput it on the page.
TestController
Here is json.cfm. All that I do with it is output the variable "json".
json.cfm
And lastly I preform my AJAX call using jQuery. In the url setting of jQuery.ajax() I just link to the controller. In my case, my controller's name is TestController, so my route with just be "test" and then I can change out the method. In my case I am calling the "testMethod" on the controller.
If you want to return json back just go to json.cfm and wrap params.json in SerializeJSON(). Then in your ajax call, do jQuery.parseJSON(). This is the only way I can think of right now to make an ajax call with ColdMVC, if there are any other techniques I would be more then happy to listen.
First I created a function on a Controller so I can return "hi" back from the AJAX call. Notice I have @view json.cfm above the function. Since ColdMVC uses routes I need to send the data to a view and cfoutput it on the page.
TestController
/**
* @accessors true
* @extends coldmvc.controller
*/
component {
/**
@view json.cfm
*/
function testMethod(){
params.json = "hi";
}
}
Here is json.cfm. All that I do with it is output the variable "json".
json.cfm
<cfoutput>#params.json#</cfoutput>
And lastly I preform my AJAX call using jQuery. In the url setting of jQuery.ajax() I just link to the controller. In my case, my controller's name is TestController, so my route with just be "test" and then I can change out the method. In my case I am calling the "testMethod" on the controller.
ajaxCall = function(){
jQuery.ajax({
url:"#coldmvc.link.to('/test')#/test?returnformat=json",
type:"GET",
success:function(data){
jQuery("body").html(data);
}
});
};
If you want to return json back just go to json.cfm and wrap params.json in SerializeJSON(). Then in your ajax call, do jQuery.parseJSON(). This is the only way I can think of right now to make an ajax call with ColdMVC, if there are any other techniques I would be more then happy to listen.
Tuesday, August 10, 2010
ColdMVC: Plugging in fckeditor
I am working on a CMS app and I wanted the fckeditor in my app, while using ColdMVC. Here's what I did to get it in my app.
I downloaded the fckeditor and put it in the public folder, like below...
app
>public
>>plugins
>>>fckeditor
Next, on a custom helper called "util.cfc", I added a function called editor().
1. Create a fckeditor bean.
2. Set the properties of the fckeditor. Specifically the basepath is really important. I used $.config.get('assetPath') to get to the directory where the fckeditor is located.
3. Lastly, I wrap the fckeditor in ColdMVC's field() so it looks like the other fields.
Finally on my view, I call the helper function editor() and pass in my value. The use case below is for the editing a layout record for a cms app.
One thing to note is that if you want to bind the fckeditor textarea to an object, so it can be used in ColdMVC's populate() for a save, you will need to prefix your instanceName in the fckeditor. I do this by wrapping the fckeditor in a helper function and use the "name" argument like this...
I downloaded the fckeditor and put it in the public folder, like below...
app
>public
>>plugins
>>>fckeditor
Next, on a custom helper called "util.cfc", I added a function called editor().
1. Create a fckeditor bean.
2. Set the properties of the fckeditor. Specifically the basepath is really important. I used $.config.get('assetPath') to get to the directory where the fckeditor is located.
3. Lastly, I wrap the fckeditor in ColdMVC's field() so it looks like the other fields.
<cffunction name="editor" access="public" output="false" returntype="string">
<cfargument name="name" required="true"/>
<cfargument name="value" required="false" default=""/>
<cfargument name="width" required="false" default="100%"/>
<cfargument name="height" required="false" default="300px"/>
<cfset local.bean = application.coldmvc.beanFactory.getBean("fckeditor")/>
<cfset local.bean.basePath = "#$.config.get('assetPath')#plugins/fckeditor/"/>
<cfset local.bean.instanceName = arguments.name/>
<cfset local.bean.value = arguments.value/>
<cfset local.bean.width = arguments.width/>
<cfset local.bean.height = arguments.height/>
<cfif not StructKeyExists(arguments,"label")>
<cfset arguments.label = $.string.humanize(arguments.name)/>
</cfif>
<cfoutput>
<cfsavecontent variable="local.field">
#local.bean.create()#
</cfsavecontent>
</cfoutput>
<cfreturn $.form.field(label=arguments.label,field=trim(local.field))/>
</cffunction>
Finally on my view, I call the helper function editor() and pass in my value. The use case below is for the editing a layout record for a cms app.
<cfoutput>
<c:form action="save" bind="layout">
<c:hidden name="id" value="#layout.id()#" />
<c:input name="name" value="#layout.name()#" />
#$.util.editor(label="Layout",name="layout.layout",value=layout.layout())#
<c:submit name="save" />
</c:form>
</cfoutput>
One thing to note is that if you want to bind the fckeditor textarea to an object, so it can be used in ColdMVC's populate() for a save, you will need to prefix your instanceName in the fckeditor. I do this by wrapping the fckeditor in a helper function and use the "name" argument like this...
<--- on my view I put in "layout.layout" as the name--->
#$.util.editor(label="Layout",name="layout.layout",value=layout.layout())#
<--- inside the editor()--->
<cfset local.bean.instanceName = arguments.name/>
Thursday, August 5, 2010
ColdMVC: Deploying my first app.
I just wanted to share some things I struggled with when deploying my first ColdMVC app.
1. Deploying the code to the server.
My web root on the hosted server looks like this:
->myApp
->coldMVC
->hyrule
2. Make sure the config.ini is setup correctly.
config.ini file
[default]
controller=route
action=render
[development]
development=true
[production]
datasource=myDataSourceName
development=false
sesURLs=true
urlPath=
assetPath=http://www.myDomain.com/myApp/public/
tagPrefix=c
In the block [production] you will see that sesURLs=true. This will get rid of /index.cfm on the tail of url. Example www.myDomain.com/public/
Next, I changed my urlPath to nothing because I want urls to not have the public in front of them. Example www.myDomain.com/
Finally, Since my urlPath doesn't point to the public folder any more all my assets ( css, js..etc) will be broken. So I point my assets back to the public folder. Examples http://www.myDomain.com/myApp/public/
Note: If you haven't already, make sure you create a default controller and action to hit. This will be excuted if somebody hits your base url. Example www.myDomain.com
3. Use apache or isapi rewrite rules to make the url prettier.
With out the /public/index.cfm at the end of url the app can't do routes. In order to solve this I had to make isapi rewrite rules to point anything after www.myDomain.com to the http://www.myDomain.com/myApp/public/index.cfm files so routes would work again.
.htaccess file
RewriteEngine on
#---redirect actions for www.myDomain.com
RewriteCond %{HTTP_HOST} ^www.myDomain.com [QSA]
RewriteCond %{SCRIPT_NAME} ^/index.cfm$
RewriteRule ^(.*)$ http://www.myDomain.com/myApp/public/index.cfm/%{REQUEST_URI} [QSA]
#---redirect assets for www.myDomain.com
RewriteCond %{HTTP_HOST} ^www.myDomain.com [QSA]
RewriteCond %{SCRIPT_NAME} !^/index.cfm$
RewriteCond %{SCRIPT_NAME} !(css|js|images)
RewriteCond %{SCRIPT_NAME} !-f
RewriteCond %{SCRIPT_NAME} !-d
RewriteRule ^(.*)$ http://www.myDomain.com/myApp/public/index.cfm/%{REQUEST_URI} [QSA,L]
4. Make sure the production environment.txt has the production text in it.
Since my app's config.ini file has block called [production] in it the environment.txt on the hosted server needs to have the text "production" in it.
5. Remember to create a datasource.
If the datasource name is not the same as your app folder name you need to add the datasource name in config.ini
[production]
datasource=myDataSourceName
Other than the isapi rewrite rules, it was my first time writing them, deploying my first ColdMVC app went well.
1. Deploying the code to the server.
My web root on the hosted server looks like this:
->myApp
->coldMVC
->hyrule
2. Make sure the config.ini is setup correctly.
config.ini file
[default]
controller=route
action=render
[development]
development=true
[production]
datasource=myDataSourceName
development=false
sesURLs=true
urlPath=
assetPath=http://www.myDomain.com/myApp/public/
tagPrefix=c
In the block [production] you will see that sesURLs=true. This will get rid of /index.cfm on the tail of url. Example www.myDomain.com/public/
Next, I changed my urlPath to nothing because I want urls to not have the public in front of them. Example www.myDomain.com/
Finally, Since my urlPath doesn't point to the public folder any more all my assets ( css, js..etc) will be broken. So I point my assets back to the public folder. Examples http://www.myDomain.com/myApp/public/
Note: If you haven't already, make sure you create a default controller and action to hit. This will be excuted if somebody hits your base url. Example www.myDomain.com
3. Use apache or isapi rewrite rules to make the url prettier.
With out the /public/index.cfm at the end of url the app can't do routes. In order to solve this I had to make isapi rewrite rules to point anything after www.myDomain.com to the http://www.myDomain.com/myApp/public/index.cfm files so routes would work again.
.htaccess file
RewriteEngine on
#---redirect actions for www.myDomain.com
RewriteCond %{HTTP_HOST} ^www.myDomain.com [QSA]
RewriteCond %{SCRIPT_NAME} ^/index.cfm$
RewriteRule ^(.*)$ http://www.myDomain.com/myApp/public/index.cfm/%{REQUEST_URI} [QSA]
#---redirect assets for www.myDomain.com
RewriteCond %{HTTP_HOST} ^www.myDomain.com [QSA]
RewriteCond %{SCRIPT_NAME} !^/index.cfm$
RewriteCond %{SCRIPT_NAME} !(css|js|images)
RewriteCond %{SCRIPT_NAME} !-f
RewriteCond %{SCRIPT_NAME} !-d
RewriteRule ^(.*)$ http://www.myDomain.com/myApp/public/index.cfm/%{REQUEST_URI} [QSA,L]
4. Make sure the production environment.txt has the production text in it.
Since my app's config.ini file has block called [production] in it the environment.txt on the hosted server needs to have the text "production" in it.
5. Remember to create a datasource.
If the datasource name is not the same as your app folder name you need to add the datasource name in config.ini
[production]
datasource=myDataSourceName
Other than the isapi rewrite rules, it was my first time writing them, deploying my first ColdMVC app went well.
Wednesday, August 4, 2010
ColdMVC: Basic CMS app request handling
I wanted to try make a cms app with ColdMVC so I took a stab at it. This is my first draft at a cms app. Below is a light weight request handler for cms views. We will break it down in a sec.
When a request begins I use the event "requestStart" to check if it's a cms page. This happens here...
As you can see above we are checking if getPath() is a cms page. getPath() gets the tail end of the url. Example: If the url read "www.mydomain.com/public/index.cfm/contact_us/", getPath() would return "contact_us/". This happens here...
If a cms page isn't found the request will run as usual. If a cms page is found it will go to render(). render() does a lot of checks.
First, we check if there is no file extension, example ".cfm", on path. If there is none I put in an "index.cfm" at the end. I do this for the next check which checks to see if the file exists.
Second, next we check if the file path actually exists in the app/views/ directory. If it does I render it. I do this because some pages might need to be coded where as other pages will be setup with a "web page generater" tool.
Third, if the file doesn't exists I can assume it's a page that was created by web page generator tool.
Lastly, I check if the page doesn't exists. I do this because my config.ini uses render() as defaults.
[default]
controller=cmsView
action=render
If someone requests "www.mydomain.com/public/index.cfm" the path won't exist. Therefore we excute the 404 handler, which is called render404().
This happens here...
If a page doesn't exists in the cms pages, an invalid controller or action is found I render404() is executed. I first check to see if a 404 page was created in the cms pages else I render my own html message.
This happens here...
As I have been going through these functions I didn't explain where the pages are getting renderer. If you noticed at the top of first block of code there was an annotation @layout cms_public. All cms pages, whether they are coded up or database driven, run through the layout cms_public.cfm. Here's what it looks like...
All database driven pages run through a view in "views/cms/view/index.cfm" which looks like this...
Thoughts on what I have so far?
/**
* @accessors true
* @extends coldmvc.Controller
* @controller cmsview
* @layout cms_public
*/
component {
property _CMSPage;
/**
* @events requestStart
*/
function requestStart(){
var page = _CMSPage.findByAddress(getPath());
/*---check if the path is a cms page---*/
if(len(page.id()) gt 0){
$.event.action("render");
$.event.controller("cmsView");
$.event.view("cms/view/index.cfm");
}
}
function render(){
var path = getPath();
var actual_path = expandPath("/app/views/#path#");
/*---handles pages that end in a slash. Ex: www.mydomain.com/public/index.cfm/products/---*/
if(right(path,1) eq "/"){
actual_path = actual_path & "index.cfm";
path = path & "index.cfm";
}
/*---if the file exists render it, else run the page's html through the cms_public layout.---*/
if(fileExists(actual_path)){
$.event.view(path);
}else{
params.page = _CMSPage.findByAddress(getPath());
if(len(params.page.id()) eq 0){
render404();
}
}
}
/**
* @events invalidController, invalidAction
*/
function render404(){
params.page = _CMSPage.findByAddress("404");
if(len(params.page.id()) eq 0){
params.page._set("html","Sorry. We couldn't find the page you were looking for.");
}
$.event.controller("cmsView");
$.event.action("render404");
$.event.view("cms/view/index.cfm");
}
function getPath(){
var path = $.event.path();
if(left(path,1) eq "/"){
path = replace(path,"/","");
}
return path;
}
}
When a request begins I use the event "requestStart" to check if it's a cms page. This happens here...
/**
* @events requestStart
*/
function requestStart(){
var page = _CMSPage.findByAddress(getPath());
/*---check if the path is a cms page---*/
if(len(page.id()) gt 0){
$.event.action("render");
$.event.controller("cmsView");
$.event.view("cms/view/index.cfm");
}
}
As you can see above we are checking if getPath() is a cms page. getPath() gets the tail end of the url. Example: If the url read "www.mydomain.com/public/index.cfm/contact_us/", getPath() would return "contact_us/". This happens here...
function getPath(){
var path = $.event.path();
if(left(path,1) eq "/"){
path = replace(path,"/","");
}
return path;
}
If a cms page isn't found the request will run as usual. If a cms page is found it will go to render(). render() does a lot of checks.
First, we check if there is no file extension, example ".cfm", on path. If there is none I put in an "index.cfm" at the end. I do this for the next check which checks to see if the file exists.
Second, next we check if the file path actually exists in the app/views/ directory. If it does I render it. I do this because some pages might need to be coded where as other pages will be setup with a "web page generater" tool.
Third, if the file doesn't exists I can assume it's a page that was created by web page generator tool.
Lastly, I check if the page doesn't exists. I do this because my config.ini uses render() as defaults.
[default]
controller=cmsView
action=render
If someone requests "www.mydomain.com/public/index.cfm" the path won't exist. Therefore we excute the 404 handler, which is called render404().
This happens here...
function render(){
var path = getPath();
var actual_path = expandPath("/app/views/#path#");
/*---handles pages that end in a slash. Ex: www.mydomain.com/public/index.cfm/products/---*/
if(right(path,1) eq "/"){
actual_path = actual_path & "index.cfm";
path = path & "index.cfm";
}
/*---if the file exists render it, else run the page's html through the cms_public layout.---*/
if(fileExists(actual_path)){
$.event.view(path);
}else{
params.page = _CMSPage.findByAddress(getPath());
if(len(params.page.id()) eq 0){
render404();
}
}
}
If a page doesn't exists in the cms pages, an invalid controller or action is found I render404() is executed. I first check to see if a 404 page was created in the cms pages else I render my own html message.
This happens here...
/**
* @events invalidController, invalidAction
*/
function render404(){
params.page = _CMSPage.findByAddress("404");
if(len(params.page.id()) eq 0){
params.page._set("html","Sorry. We couldn't find the page you were looking for.");
}
$.event.controller("cmsView");
$.event.action("render404");
$.event.view("cms/view/index.cfm");
}
As I have been going through these functions I didn't explain where the pages are getting renderer. If you noticed at the top of first block of code there was an annotation @layout cms_public. All cms pages, whether they are coded up or database driven, run through the layout cms_public.cfm. Here's what it looks like...
<cfoutput>
< !DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en-us" xmlns="http://www.w3.org/1999/xhtml">
<cfif structKeyExists(params,"page")>
#page.html()#
<cfelse>
#render()#
</cfif>
</html>
</cfoutput>
All database driven pages run through a view in "views/cms/view/index.cfm" which looks like this...
<cfoutput>#page.html()#</cfoutput>
Thoughts on what I have so far?
Saturday, July 24, 2010
ColdMVC: Flatten an array of objects with children.
In record based systems "non object based" if you wanted to store a parent/child relationship you usually stored a parent_id on the same table.
Example:
CMS example showing a page table where a page can have many pages underneath it.
Page table.
ID,Name,Address,Parent_ID
1,Products,products/,null
2,Tiles,products/tiles/,1
Then in order to simulate an object based system, you usually loop the query and put the records in structs of structs.
Example.
result = {
id="1",
name="Products",
address="products/",
children=[
{
id="1",
name="Products",
address="products/",
children=[]
}
]
}
Notice there is children an array.
Using ColdMVC we actually start with "struct of structs" or object based, instead of starting with a query. So we need to take the objects array, we are using array of objects because that is what is return from an hql query, and pull out the children and put them in the array, thus flattening the tree.
To do this I run it through a helper function I made below.
You will notice I add a property called "treeDepth". In order to use the function you need to add a property to the model cfc called "treeDepth". Don't worry about it being added to db, if it's not mapped in hibernate file it won't be added to the db. I use the treeDepth property to know how far in a child object is. Technically...you don't need this, but I find a very handy.
Example:
CMS example showing a page table where a page can have many pages underneath it.
Page table.
ID,Name,Address,Parent_ID
1,Products,products/,null
2,Tiles,products/tiles/,1
Then in order to simulate an object based system, you usually loop the query and put the records in structs of structs.
Example.
result = {
id="1",
name="Products",
address="products/",
children=[
{
id="1",
name="Products",
address="products/",
children=[]
}
]
}
Notice there is children an array.
Using ColdMVC we actually start with "struct of structs" or object based, instead of starting with a query. So we need to take the objects array, we are using array of objects because that is what is return from an hql query, and pull out the children and put them in the array, thus flattening the tree.
To do this I run it through a helper function I made below.
<cffunction name="flattenArrayTree" access="public" output="false" returntype="array">
<cfargument name="array" required="true"/>
<cfargument name="result" required="false" default="#[]#"/>
<cfargument name="treeDepth" required="false" default="0"/>
<cfargument name="childrenPropertyName" required="false" default="children" hint="A property with an array of child objects."/>
<cfset var local = {}/>
<cfset var i = ""/>
<cfloop from="1" to="#arrayLen(arguments.array)#" index="i">
<cfset local.object = arguments.array[i]/>
<cfset local.object.setTreeDepth(arguments.treeDepth)/>
<cfset arrayAppend(arguments.result,local.object)>
< !---make sure the "children" property exists is in the object--->
<cfif not structKeyExists(local.object,"set"&arguments.childrenPropertyName)>
<cfthrow detail="The argument childrenPropertyName which is currently #arguments.childrenPropertyName# does not exist as a property in the object"/>
< /cfif>
<cfif arrayLen(local.object._get(arguments.childrenPropertyName)) gt 0>
<cfset arguments.treeDepth++/>
<cfset arguments.result = flattenArrayTree(local.object._get(arguments.childrenPropertyName),arguments.result,arguments.treeDepth)/>
<cfset arguments.treeDepth--/>
< /cfif>
< /cfloop>
<cfreturn arguments.result/>
< /cffunction>
You will notice I add a property called "treeDepth". In order to use the function you need to add a property to the model cfc called "treeDepth". Don't worry about it being added to db, if it's not mapped in hibernate file it won't be added to the db. I use the treeDepth property to know how far in a child object is. Technically...you don't need this, but I find a very handy.
Wednesday, July 7, 2010
ColdMVC: Parse checkboxes or radios generically
I ran into an interesting issue awhile, back. I wanted to edit a product and click on checkboxes for one to many relationships to colors, categories, and sizes. When I post the form to the ProductController save() I wanted a generic way to convert checkbox values (which are ids) to actually objects. Below are the steps I took followed by the code.
First, I call private functions to parse the specific checkbox ids ( Ex. parseCategories()), but they all just call parseResource().
Next, while in parseResource() I look into the variables scope for the model (Ex. _Size) to dynamically get the object by using findByID().
Lastly, I append the object to an array and populate the Product object and save it.
ProductController.cfc
I wanted to share this just in case someone else is running into the issue.
First, I call private functions to parse the specific checkbox ids ( Ex. parseCategories()), but they all just call parseResource().
Next, while in parseResource() I look into the variables scope for the model (Ex. _Size) to dynamically get the object by using findByID().
Lastly, I append the object to an array and populate the Product object and save it.
ProductController.cfc
/**
* @accessors true
* @action list
* @extends coldmvc.Controller
*/
component {
property _Size;
property _Color;
property _Category;
function save() {
var product = _Product.new();
params.product.categories = parseCategories(params.product.categories);
params.product.sizes = parseSizes(params.product.sizes);
params.product.colors = parseColors(params.product.colors);
product.populate(params.product);
product.save();
redirect({controller="product",action="setup"},"productID=#product.id()#");
}
private array function parseCategories(string categoryIDs) {
return parseResource("Category",arguments.categoryIDs);
}
private array function parseSizes(string sizeIDs) {
return parseResource("Size",arguments.sizeIDs);
}
private array function parseColors(string colorIDs) {
return parseResource("Color",arguments.colorIDs);
}
private array function parseResource(string resource, string resourceIDs){
var resources = $.string.toArray(arguments.resourceIDs);
var result = [];
var i = "";
for (i=1; i <= arrayLen(resources); i++) {
arrayAppend(result, variables["_#arguments.resource#"].findByID(resources[i]));
}
return result;
}
}
I wanted to share this just in case someone else is running into the issue.
Sunday, April 11, 2010
ColdMVC: Create your own Helpers.
I wanted to try extending ColdMVC's helpers and create my own helper that formatted stuff for me and it turned out to be quite simple.
First, I created my own directory in my project called "helpers".
Second, I added a cfc named "format".
Third, I extended the ViewHelper from ColdMVC. Not sure, If this is the correct Helper Util class I am suppose to be using...but it worked.
Lastly, I used my new helper function:
If you noticed in money() I set a default value of zero. For some odd reason when I put "product.getPrice()" in for the amount argument it has a value of [empty string] and it throws an error. The error says "The AMOUNT parameter to the money function is required but was not passed in.". But clearly there is a value of [empty string]. If any one knows what up give me hollar.
First, I created my own directory in my project called "helpers".
Second, I added a cfc named "format".
Third, I extended the ViewHelper from ColdMVC. Not sure, If this is the correct Helper Util class I am suppose to be using...but it worked.
<cfcomponent extends="coldmvc.utils.ViewHelper">
<!------>
<cffunction name="money" access="public" output="false" returntype="any">
<cfargument name="amount" required="false" default="0"/>
<cfreturn dollarFormat(arguments.amount)/>
</cffunction>
<!------>
</cfcomponent>
Lastly, I used my new helper function:
#$.format.money(product.getPrice())#
If you noticed in money() I set a default value of zero. For some odd reason when I put "product.getPrice()" in for the amount argument it has a value of [empty string] and it throws an error. The error says "The AMOUNT parameter to the money function is required but was not passed in.". But clearly there is a value of [empty string]. If any one knows what up give me hollar.
Subscribe to:
Posts (Atom)