Skip to content

cfwheels validating hasmanycheckbox – verify at least one checked

2013 April 2

cfwheels-logoIn cfwheels if you have a hasMany relationship and you are using the hasmanycheckbox to display your checkboxes you might want to make sure that the user checks at least one of the checkboxes.

Here’s one way to do that. Here’s an example where we have a relationship where 1 Reservation can have have many TechnologySelections (which is then tied to table called Technologies which contains all the possible technologies that can be reserved).

—– Reserveration.cfc MODEL ——-


	
		
			hasMany(name="TechnologySelections", shortcut="Technologies");
			validate(method="ValidateTechSelections");
		
	
	
	    <cfif arrayIsEmpty(this.TechnologySelections)>
	         <cfset addError(property="TechnologySelections", message="Please select at least one technology.") />
	     </cfif>
       

—– TechnologySelection.cfc MODEL ——-


	
		
			belongsTo("Reservation");
			belongsTo("Technology");
		
	

In the Reservation.cfc I’ve created a custom validation called ValidateTechSelections using the validate tag. Then I created the function to do this custom validation which checks the array this.TechnologySelections to see if it’s empty. If the array is empty then it sets the addError for the property TechnologySelections. CFWheels uses the name of the hasMany model for the array variable. You could also use the ColdFusion tag ArrayLen to get the length of the this.TechnologySelections array and validate it to be greater than 1 or between 2 values if you wanted.

I added a similar example to the validate documentation in the CFWheels framework on github so hopefully when/if that gets added to the cfwheels website it will help give another example right in the official documentation.

cfwheels error messages with nested properties (e.g. has many, one to many)

2013 April 2

cfwheels-logoThe cfwheels documentation is really good, but it leaves out a few of the more difficult but useful scenarios. One of which is how to handle server side form error messages when you have nested properties and has-many/one-to-many relationships. This is how I got the error messages to show for me.

Here is my setup, I’ve simplified it to show how the error messages work:

—— /model/Teacher.cfc MODEL ——

<cfcomponent extends="Model">
	<cffunction name="init">
	    <cfset hasMany(name="Courses", dependent="deleteAll") />
            <cfset nestedProperties(associations="Courses", allowDelete=true) />
	</cffunction>
</cfcomponent>

—— /model/Course.cfc MODEL ——

<cfcomponent extends="Model">
	<cffunction name="init">
	     <cfset belongsTo("Teacher") />
	     <cfset validatePresenceOf(method="coursenumber") />
	</cffunction>
</cfcomponent>

—— /controller/Assign.cfc CONTROLLER——

	      
<cffunction name="index">
     <cfset var newCourses= [ model("Course").new() ] />
     <cfset newTeacher = model("Teacher").new(Courses=newCourse) />
</cffunction>

<cffunction name="create">
   <cfif TechRequest.save()>
	<!--- save succeeded show thank you page (create view) --->
   <cfelse>
	 <!---if error when trying to save show the errors on the index page --->			
        <cfset renderPage(action="index") />
   </cfif>
</cffunction>

—— /views/Assign/index.cfm VIEW——

     
    #errorMessagesFor("newTeacher")#

    #startFormTag(action="create", controller="Assign")#
       #textField(objectName="newTeacher", property="FirstName", label="First Name")#
       #textField(objectName="newTeacher", property="LastName", label="First Name")#
       #includePartial(newTeacher.Courses)#
    #endFormTag()#

—— /views/Assign/_Course.cfm PARTIAL——

     
    #errorMessageOn(objectName="newTeacher['Courses'][#arguments.current#]", property="coursenumber")#

    #textField(objectName="newTeacher", property="coursenumber", position=arguments.current)#

So as you can see above the nested errors need to be referenced from the _Course.cfm partial file. They also need to be referenced using the object’s array of courses and the errorMessagesOn cfwheels tag. This looks like:

    #errorMessageOn(objectName="newTeacher['Courses'][#arguments.current#]", property="coursenumber")#

The arguments.current variable is a number which references the course that it is cycling through when it renders the partial. In my example above this will always be 1 because I created only 1 new course in the Assign controller for the newTeacher object.

FIX – carousel bootstrap does not have slide transition in IE

2013 January 30

Seems crazy that the bootstrap carousel feature’s slide transition does not work in IE.

If you do a google search tons of sites have solutions for this, but some are wrong and others just point you to the fix without any explanation.  I used the solution from Barryvdh here.  I’ve only tested it in IE 8, and apparently for IE 7 you might need to make a change to this code but I didn’t do that.

Here’s what I did to fix the slide transition issue (only tested in IE 8, you’ll want to test others):

  • Go to the bootstrap website’s customization page and make sure all the features are selected (that is if you need everything), EXCEPT for the jQuery plugin for Carousel.  Remove that one.
    jquerycarousel
  • Download the customized file and use the bootstrap.min.js file as you normally would on your site.
  • Next download the bootstrap-carousel.js file from the bootstrap github site https://github.com/twitter/bootstrap/blob/master/js/bootstrap-carousel.js
  • Make the changes to the bootstrap-carousel.js file as seen in these commits: https://github.com/Barryvdh/bootstrap/commit/8b294f0c0184eb7111ef6da6046d4d1f33ea7ba3
  • Add your updated bootstrap-carousel.js file to your site after you load the bootstrap.min.js
  • I did this on 1/30/2013, and here is my updated bootstrap-carousel.js file, keep in mind that this will probably be out of date with the next release of bootstrap, but in any event it might be helpful to see:
/* ==========================================================
* bootstrap-carousel.js v2.2.2
* http://twitter.github.com/bootstrap/javascript.html#carousel
* ==========================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================== */

!function ($) {

"use strict"; // jshint ;_;

/* CAROUSEL CLASS DEFINITION
* ========================= */

var Carousel = function (element, options) {
this.$element = $(element)
this.options = options
this.options.pause == 'hover' && this.$element
.on('mouseenter', $.proxy(this.pause, this))
.on('mouseleave', $.proxy(this.cycle, this))
}

Carousel.prototype = {

cycle: function (e) {
if (!e) this.paused = false
this.options.interval
&& !this.paused
&& (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
return this
}

, to: function (pos) {
var $active = this.$element.find('.item.active')
, children = $active.parent().children()
, activePos = children.index($active)
, that = this

if (pos > (children.length - 1) || pos < 0) return if (this.sliding) { return this.$element.one('slid', function () { that.to(pos) }) } if (activePos == pos) { return this.pause().cycle() } return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos]))
}

, pause: function (e) {
if (!e) this.paused = true
if (this.$element.find('.next, .prev').length && $.support.transition.end) {
this.$element.trigger($.support.transition.end)
this.cycle()
}
clearInterval(this.interval)
this.interval = null
return this
}

, next: function () {
if (this.sliding) return
return this.slide('next')
}

, prev: function () {
if (this.sliding) return
return this.slide('prev')
}

, slide: function (type, next) {
//**************************************ADDED*********************************//
if(!$.support.transition && this.$element.hasClass('slide')) {
this.$element.find('.item').stop(true, true); //Finish animation and jump to end.
}
//**************************************ADDED*********************************//
var $active = this.$element.find('.item.active')
, $next = next || $active[type]()
, isCycling = this.interval
, direction = type == 'next' ? 'left' : 'right'
, fallback = type == 'next' ? 'first' : 'last'
, that = this
, e

this.sliding = true

isCycling && this.pause()

$next = $next.length ? $next : this.$element.find('.item')[fallback]()

e = $.Event('slide', {
relatedTarget: $next[0]
})

if ($next.hasClass('active')) return

if ($.support.transition && this.$element.hasClass('slide')) {
this.$element.trigger(e)
if (e.isDefaultPrevented()) return
$next.addClass(type)
$next[0].offsetWidth // force reflow
$active.addClass(direction)
$next.addClass(direction)
this.$element.one($.support.transition.end, function () {
$next.removeClass([type, direction].join(' ')).addClass('active')
$active.removeClass(['active', direction].join(' '))
that.sliding = false
setTimeout(function () { that.$element.trigger('slid') }, 0)
})
//**************************************ADDED*********************************//
}else if(!$.support.transition && this.$element.hasClass('slide')) {
this.$element.trigger(e)
if (e.isDefaultPrevented()) return
$active.animate({left: (direction == 'right' ? '100%' : '-100%')}, 600, function(){
$active.removeClass('active')
that.sliding = false
setTimeout(function () { that.$element.trigger('slid') }, 0)
})
$next.addClass(type).css({left: (direction == 'right' ? '-100%' : '100%')}).animate({left: '0'}, 600, function(){
$next.removeClass(type).addClass('active')
})
//**************************************ADDED*********************************//
} else {
this.$element.trigger(e)
if (e.isDefaultPrevented()) return
$active.removeClass('active')
$next.addClass('active')
this.sliding = false
this.$element.trigger('slid')
}

isCycling && this.cycle()

return this
}

}

/* CAROUSEL PLUGIN DEFINITION
* ========================== */

var old = $.fn.carousel

$.fn.carousel = function (option) {
return this.each(function () {
var $this = $(this)
, data = $this.data('carousel')
, options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option)
, action = typeof option == 'string' ? option : options.slide
if (!data) $this.data('carousel', (data = new Carousel(this, options)))
if (typeof option == 'number') data.to(option)
else if (action) data[action]()
else if (options.interval) data.cycle()
})
}

$.fn.carousel.defaults = {
interval: 5000
, pause: 'hover'
}

$.fn.carousel.Constructor = Carousel

/* CAROUSEL NO CONFLICT
* ==================== */

$.fn.carousel.noConflict = function () {
$.fn.carousel = old
return this
}

/* CAROUSEL DATA-API
* ================= */

$(document).on('click.carousel.data-api', '[data-slide]', function (e) {
var $this = $(this), href
, $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
, options = $.extend({}, $target.data(), $this.data())
$target.carousel(options)
e.preventDefault()
})

}(window.jQuery);

The RPC server is unavailable Sharepoint 2013 Preview Configuration Wizard Fails on Install

2012 July 27

On step 3 of the Sharepoint 2013 Preview Configuration Wizard it would fail with the error:

The RPC server is unavailable

I then checked the log file and found the following:

Failed to create the configuration database.
Additional exception information: An error occurred while getting information about the user USERNAME at server DOMAINNAME: The RPC server is unavailable

Everyone on the web says the same thing: check the access rights to add DB’s on the SQL database, do you have proper access rights on the servers, do you have such and such ports open, is your RPC service running.  I checked all of these and opened everything up…

BUT if you are like me you tried all those things and it still failed!  Luckily, I realized the one stupid thing that I forgot…

Here’s my solution

Make sure you are logged onto the server where you are running the Configuration Wizard with a domain account, and to be safe, I ran the install with the same domain account that I want to run the Sharepoint services with.

I hope this helps save you the 8 hours of work I spent trying to figure this problem out.

jquery change value of input field

2012 May 30
by mark

Below I am changing the value of an input by using the id of the field using jquery

$('#MyFieldID').val('This is the new value');

textarea – maxlength equivalent – easy way of limiting the max number of characters

2012 April 3

The easiest way to limit the maximum length someone can type into a textarea field of your form is to do the following:

<textarea name=”mytextarea” id=”mytextarea” cols=”50″ rows=”4″ onkeypress=”return (this.value.length < 20);” >

Where 20 is the maximum number of characters you want to show.  This seems to work well on Chrome and IE.  I found a lot of other examples on the web that require 30 lines of code, but this is the simplest way, just using the onkeypress event.

onkeypress=”return (this.value.length < 20);”

 

DFS Location is not available – The network location cannot be reached – Can’t Open DFS Shared Folder – Windows 2008 Server

2012 February 7
by mark

This is a frustrating error you might run into this error on Windows Vista and Windows 7 when you try to access a DFS linked shared folder.  It says something like Network Location Unavailable, or Location is not available, or The network location cannot be reached on the different flavors of Windows.

Solution 1
Change your client computer to be on the same domain name as the server you’re trying to access.  For example, if your server’s FQDN (domain name) is myserver.yakimadev.com and your clients computer is myclient.microsoft.com, then you will need to change your client to have the same DNS suffix as your server (yakimadev.com in this example).  So change your computer to be myclient.yakimadev.com.  This should solve the problem, unless you already have incorrect data in the “Append DNS Suffixs” in the TCP/IP settings.  If this is the case, or you can’t change the DNS name of your client then you need to move to solution 2.

Solution 2
If you can’t do solution 1, or you already have suffixes, then you need to do the following:

  1. Open Networking Properties, one way to get there on Windows 7 is by clicking Start then typing “Network” in the search, and then right clicking on Network and selecting properties.
  2. Then click the link in the top left corner “Change Adapter Settings”
  3. Right click on your network adapter and select “Properties”
  4. Click on Internet Protocol Version 4 (TCP/IPv4) and then click on the Properties button
  5. Click on the Advanced button
  6. Click on the DNS tab
  7. Check the Radio button “Append these DNS suffixes (in order):”
  8. Click the Add button and add the suffix of your server.  In the example I use in solution one, I have a server called myserver.yakimadev.com, so I would add an entry for “yakimadev.com” and move that to the top.
  9. Click on ok, and then ok, and then close
  10. Disconnect your mapping to your DFS if you are currently mapped, and then remap it.
  11. It should work at this point!

A little more explanation
I’m not a DFS expert nor am I a networking expert, but from what I can tell when you click on a DFS linked folder the DFS server returns the host name of the server that is sharing that folder.  Your client receives the host name and tries to append the host name to the DNS suffix that it is using and fails if your server has a different DNS suffix than your client.  This process happens if you have the radio button in the image above checked that says “Append primary connection specific DNS suffixes” and also have the checkbox under it checked.  Once you change this to “Append these DNS suffixes” and type in the suffix of your server  you client will then take the host name of the server and append it to the DNS suffix you provided and find the server correctly.

 

Require Field if certain radio buttons are checked in jQuery Validation Plugin

2011 November 18

I have a form with 3 radio buttons:

<input id="Desktop" name="Usage" type="radio" value="Desktop" /> Desktop
<input id="Laptop" name="Usage" type="radio" value="Laptop" /> Laptop
<input id="iPad" name="Usage" type="radio" value="iPad" /> iPad

If one of the first two radio buttons are checked then I dynamically ask the user if they are using a PC or a MAC, which is a set of radio’s called MacOrPC. I want the PC/MAC question to be required only if the Desktop or Laptop radio buttons are checked. To do this, I think I figured out the syntax in the jQuery Validation Plugin. Here’s the rule syntax I used that seems to work using the ampersand:

rules: {
MacOrPC: {required: "#Desktop:checked" & "#Laptop:checked"}
}

How to select elements based on partial id in jQuery

2011 November 16
by mark

I had a bunch of images on a webpage that had id’s that began with myimage and then had a number, like myimage1, myimage2, myimage3.  I wanted to select them all and change the image.  To do this you can use 1 line of the code:
$('img[id*=myimage]').attr("src", "/images/differentimg.jpg");
In this code you are telling jQuery to look for any img tags on your webpage that have the word myimage in their id and then change the src tag of the image to differentimg.jpg.

How to change the error message class for the jquery form field validation plugin

2011 November 11
by mark

If you want to change the look and feel of error messages of the jquery validation plugin you need to set errorClass to the name of the class you want to use.  So for example I wanted to change my error messages font color to be red so here is what I did in the head section of the webpage, I added a class called errors and then set the errorClass to be errors:

<style type="text/css">
 .errors {color:#900};
</style>

<script type="text/javascript">
$(document).ready(function() {
 $('#EventForm').validate({
   errorClass:"errors",
   rules: {
     FirstName: {required: true}
   }
 });
});
</script>