Limit the Number of Values in a Text Field

Hi guys,

I can’t seem to find a way to only allow the number of characters inputted in a text field to a number I choose. For example I have a Input date section with a DD text field MM and YY on each of the three text fields i want the input characters to only allow 2 numbers is there a way of doing this?

Thanks again,

Matt. 

Yep, just write a listener that enforces a length:

local function textListener( event ) local target = event.target local maxLen = target.maxLen local text = event.text if ( event.phase == "began" ) then print( text ) else if( string.len( text ) \> maxLen ) then target.text = string.sub( text, 1, maxLen ) end end end -- Create text field local test = native.newTextField( 150, 150, 180, 30 ) test.maxLen = 2 test:addEventListener( "userInput", textListener )

Hi there I attempted to try your textListener but seem to keep getting this error…

attempt to compare nil with number

Any ideas on what this means?

Thanks again,

Matt.

This is probably a typo in my example.  I didn’t test it, but wrote it off the cuff.  The console should tell you the line where the error occurred.  Track the variables involved till you find the problem.  The premise of the solution is what you need to do.   The implementation is up to you.

I just ran the code I gave and it works as expected, so you’ve probably got an issue in your own code.

Questions:

  1. What version of Corona are you running? I ran and tested this with Corona 2015.2625

  2. Where does it fail? Simulator or device?  If simulator, OS X right?

  3. Show your code.  Clearly (since I cut and pasted this and it worked), you’ve either retyped my example or integrated parts of it into your code and it now fails.  We need to see this to debug.  

Hmm odd…

  1. I’m running Corona Simulator version 14.2511.0

  2. I ran it on my device which was Andriod, this is because i’m using windows and the simulator wouldn’t run the textfields in the simulator.

  3. This is how I integrated your code into mine.

[lua]


– incidentReportingPg1.lua


local composer = require( “composer” )

local scene = composer.newScene()

local widget = require( “widget” )

local myData = require( “myData” )

local function btnPrevious( event )

    composer.gotoScene( “incidentReportingPg1”, { effect=“slideRight”, time=800} )

end

function scene:create( event )

local sceneGroup = self.view

local function textListener( event )

   local target = event.target

   local maxLen = target.maxLen

   local text = event.text

   

   if ( event.phase == “began” ) then

     print( text )

   else

      if( string.len( text ) > maxLen ) then

         target.text = string.sub( text, 1, maxLen ) 

      end

   end

end

–bg

local bg = display.newRect( 0, 0, display.contentWidth, display.contentHeight )

bg.anchorX = 0

bg.anchorY = 0

bg:setFillColor( 0.9, 0.9, 0.9 ) – white

sceneGroup:insert( bg )

–titleHeader

local titleHeader = display.newImage( “titleHeader.png” )

titleHeader:translate( 160, -22 )

–title

local title = display.newText( “Incident Reporting”, 0, 0, native.systemFont, 32 )

title:setFillColor( 0 ) – black

title.x = display.contentWidth * 0.5

title.y = -25

–textPage

local textPage = display.newText(“Page 2”, 

280,130, display.contentWidth -25 , display.contentHeight * 0.5, native.systemFont, 15 )

textPage:setFillColor( 0, 0, 0 )

–textSectionA

local textSectionA = display.newText(“Section A: About the Incident”, 

172, 155, display.contentWidth, display.contentHeight * 0.5, native.systemFont, 20 )

textSectionA:setFillColor( 0, 0, 0 )

sceneGroup:insert( textSectionA )

–textDate

local textDate = display.newText(“Incident Date: (DD/MM/YY)”, 

175, 190, display.contentWidth, display.contentHeight * 0.5, native.systemFont, 13 )

textDate:setFillColor( 0, 0, 0 )

sceneGroup:insert( textDate )

–textBoxDay

local textBoxDay = native.newTextField( 54, 110, 75, 40 )

textBoxDay.size = 20

textBoxDay:addEventListener( “userInput”, textListener )

textBoxDay.inputType = “number”

sceneGroup:insert( textBoxDay )

–forwardSlash

local forwardSlash = display.newImage( “forwardSlash.png” )

forwardSlash:translate( 105, 110 )

sceneGroup:insert( forwardSlash )

–textBoxMonth

local textBoxMonth = native.newTextField( 156, 110, 75, 40 )

textBoxMonth.size = 20

textBoxMonth:addEventListener( “userInput”, textListener )

textBoxMonth.inputType = “number”

sceneGroup:insert( textBoxMonth )

–forwardSlash

local forwardSlash = display.newImage( “forwardSlash.png” )

forwardSlash:translate( 207, 110 )

sceneGroup:insert( forwardSlash )

–textBoxYear

local textBoxYear = native.newTextField( 258, 110, 75, 40 )

textBoxYear.size = 20

textBoxYear:addEventListener( “userInput”, textListener )

textBoxYear.inputType = “number”

sceneGroup:insert( textBoxYear )

–textTime

local textTime = display.newText(“Incident Time: (HH:MM)”, 

175, 270, display.contentWidth, display.contentHeight * 0.5, native.systemFont, 13 )

textTime:setFillColor( 0, 0, 0 )

sceneGroup:insert( textTime )

–textBoxHour

local textBoxHour = native.newTextField( 54, 190, 75, 40 )

textBoxHour.size = 20

textBoxHour:addEventListener( “userInput”, textListener )

textBoxHour.inputType = “number”

sceneGroup:insert( textBoxHour )

–semiColon

local semiColon = display.newImage( “semiColon.png” )

semiColon:translate( 105, 190 )

sceneGroup:insert( semiColon )

–textBoxMinute

local textBoxMinute = native.newTextField( 156, 190, 75, 40 )

textBoxMinute.size = 20

textBoxMinute:addEventListener( “userInput”, textListener )

textBoxMinute.inputType = “number”

sceneGroup:insert( textBoxMinute )

–Divider

local divider = display.newImage( “titleHeader.png” )

divider:translate( 160, 240 )

sceneGroup:insert( divider )

–textWasThis

local textWasThis = display.newText(“Was this an incident that caused harm?”, 

212, 422, display.contentWidth, display.contentHeight * 0.5, native.systemFont, 13 )

textWasThis:setFillColor( 0, 0, 0 )

sceneGroup:insert( textWasThis )

–textEgPer

local textEgPer = display.newText(“eg personal harm or damage to property”, 

212, 437, display.contentWidth, display.contentHeight * 0.5, native.systemFont, 11 )

textEgPer:setFillColor( 0, 0, 0 )

sceneGroup:insert( textEgPer )

–textWasThisA

local textWasThisA = display.newText(“Was this a Near Miss (No Harm)?”, 

212, 480, display.contentWidth, display.contentHeight * 0.5, native.systemFont, 13 )

textWasThisA:setFillColor( 0, 0, 0 )

sceneGroup:insert( textWasThisA )

– Image sheet options and declaration

local options = {

    width = 26,

    height = 26,

    numFrames = 2,

    sheetContentWidth = 26,

    sheetContentHeight = 52

}

local checkboxSheet = graphics.newImageSheet( “checkboxSheet.png”, options )

– Create a group for the radio button set

local radioGroup = display.newGroup()

– Create two associated radio buttons (inserted into the same display group)

local radioButton1 = widget.newSwitch

{

    left = 20,

    top = 300,

    style = “radio”,

    id = “RadioButton1”,

    width = 26,

    height = 26,

    onPress = onSwitchPress,

    sheet = checkboxSheet,

    frameOff = 1,

    frameOn = 2

}

radioGroup:insert( radioButton1 )

sceneGroup:insert( radioButton1 )

local radioButton2 = widget.newSwitch

{

    left = 20,

    top = 353,

    style = “radio”,

    id = “RadioButton2”,

    width = 26,

    height = 26,

    onPress = onSwitchPress,

    sheet = checkboxSheet,

    frameOff = 1,

    frameOn = 2

}

radioGroup:insert( radioButton2 )

sceneGroup:insert( radioButton2 )

local function OnbtnNext( event )

      if event.phase == “ended” then

            local radioOn = false

            local textFilled = true

            myData.dateDay = textBoxDay.text

            myData.dateMonth = textBoxMonth.text

            myData.dateYear = textBoxYear.text

            myData.timeHour = textBoxHour.text

            myData.timeMinute = textBoxMinute.text

            if radioButton1.isOn == true then

            myData.IRb1 = “Yes”

                  radioOn = true

          end

            if radioButton2.isOn == true then

           myData.IRb1 = “No (Near Miss)”

                  radioOn = true

            end

      if textBoxDay.text == “” or textBoxDay.text == nil or 

          textBoxMonth.text == “” or textBoxMonth.text == nil or

      textBoxYear.text == “” or textBoxYear.text == nil or

            textBoxHour.text == “” or textBoxHour.text == nil or

          textBoxMinute.text == “” or textBoxMinute.text == nil then

                  textFilled = false

           end

            if radioOn and textFilled then

                   composer.gotoScene( “incidentReportingPg3”, { effect=“slideLeft”, time=800,} )

            else

                  local msg

                  if radioOn == false and textFilled == false then

                        msg = “No input in checkbox(s) and textbox(s)”

                  else

                        if radioOn then

                              msg = “No input in textbox(s)”

                        else

                              msg = “No input in checkbox(s)”

                        end

                  end

                  local alert = native.showAlert( “Warning”, "ERROR: "…msg, { “OK” }, onComplete)

            end

       

      end

      return true

end

–btnPrevious

local btnPrevious = widget.newButton

{

   width = 150,

   height = 40,

   defaultFile = “btnPrevious.png”,

   onEvent = btnPrevious

}

btnPrevious.x = 84

btnPrevious.y = 445

–btnNext

local btnNext = widget.newButton

{

   width = 150,

   height = 40,

   defaultFile = “btnNext.png”,

   onEvent = OnbtnNext

}

btnNext.x = 235

btnNext.y = 445

–sceneGroup

sceneGroup:insert( titleHeader )

sceneGroup:insert( title )

sceneGroup:insert( textPage )

sceneGroup:insert( btnNext )

sceneGroup:insert( btnPrevious )

end 

function scene:show( event )

local sceneGroup = self.view

end

function scene:hide( event )

local sceneGroup = self.view

end

function scene:destroy( event )

local sceneGroup = self.view

end


– Listener setup

scene:addEventListener( “create”, scene )

scene:addEventListener( “show”, scene )

scene:addEventListener( “hide”, scene )

scene:addEventListener( “destroy”, scene )


return scene

[/lua]

Thanks again,

Matt.

Yeah.  I see the problem.  You didn’t follow my example completely.  You need to tell each text object how long you want it to be (maxLen) so the listener code can look it up.

For example, you have this:

--textBoxDay local textBoxDay = native.newTextField( 54, 110, 75, 40 ) textBoxDay.size = 20

but need to do this:

--textBoxDay local textBoxDay = native.newTextField( 54, 110, 75, 40 ) textBoxDay.size = 20 textBoxDay.maxLen = 2 -- Specify a maxLen field for all of your fields or my code won't work

Note: You could have debugged this by looking at the error message you got.  It surely complained about this line in the listener:

if( string.len( text ) \> maxLen ) then

Are you familiar with logcat?  If not, I strongly advice learning to use it as it will help with debugging on your Android device.

Ah I see, i’m still having issues. This time I ran it and when I selected one of my text fields sure enough I could only write two characters however, when I either deselected the text field or clicked on one of the other text fields I got a runtime error.

This time it says…

28:bad argument #1 to ‘len’ (string expected, got nil)

Any ideas here, also I’ll take a look at that logcat thanks for sharing it.

Matt.

Just verify there is something in text before operating on it:

if( text and string.len( text ) \> maxLen ) then -- aborts early if text is nil target.text = string.sub( text, 1, maxLen ) end

This is exactly what I was looking for thank you for your help.

Matt.

Yep, just write a listener that enforces a length:

local function textListener( event ) local target = event.target local maxLen = target.maxLen local text = event.text if ( event.phase == "began" ) then print( text ) else if( string.len( text ) \> maxLen ) then target.text = string.sub( text, 1, maxLen ) end end end -- Create text field local test = native.newTextField( 150, 150, 180, 30 ) test.maxLen = 2 test:addEventListener( "userInput", textListener )

Hi there I attempted to try your textListener but seem to keep getting this error…

attempt to compare nil with number

Any ideas on what this means?

Thanks again,

Matt.

This is probably a typo in my example.  I didn’t test it, but wrote it off the cuff.  The console should tell you the line where the error occurred.  Track the variables involved till you find the problem.  The premise of the solution is what you need to do.   The implementation is up to you.

I just ran the code I gave and it works as expected, so you’ve probably got an issue in your own code.

Questions:

  1. What version of Corona are you running? I ran and tested this with Corona 2015.2625

  2. Where does it fail? Simulator or device?  If simulator, OS X right?

  3. Show your code.  Clearly (since I cut and pasted this and it worked), you’ve either retyped my example or integrated parts of it into your code and it now fails.  We need to see this to debug.  

Hmm odd…

  1. I’m running Corona Simulator version 14.2511.0

  2. I ran it on my device which was Andriod, this is because i’m using windows and the simulator wouldn’t run the textfields in the simulator.

  3. This is how I integrated your code into mine.

[lua]


– incidentReportingPg1.lua


local composer = require( “composer” )

local scene = composer.newScene()

local widget = require( “widget” )

local myData = require( “myData” )

local function btnPrevious( event )

    composer.gotoScene( “incidentReportingPg1”, { effect=“slideRight”, time=800} )

end

function scene:create( event )

local sceneGroup = self.view

local function textListener( event )

   local target = event.target

   local maxLen = target.maxLen

   local text = event.text

   

   if ( event.phase == “began” ) then

     print( text )

   else

      if( string.len( text ) > maxLen ) then

         target.text = string.sub( text, 1, maxLen ) 

      end

   end

end

–bg

local bg = display.newRect( 0, 0, display.contentWidth, display.contentHeight )

bg.anchorX = 0

bg.anchorY = 0

bg:setFillColor( 0.9, 0.9, 0.9 ) – white

sceneGroup:insert( bg )

–titleHeader

local titleHeader = display.newImage( “titleHeader.png” )

titleHeader:translate( 160, -22 )

–title

local title = display.newText( “Incident Reporting”, 0, 0, native.systemFont, 32 )

title:setFillColor( 0 ) – black

title.x = display.contentWidth * 0.5

title.y = -25

–textPage

local textPage = display.newText(“Page 2”, 

280,130, display.contentWidth -25 , display.contentHeight * 0.5, native.systemFont, 15 )

textPage:setFillColor( 0, 0, 0 )

–textSectionA

local textSectionA = display.newText(“Section A: About the Incident”, 

172, 155, display.contentWidth, display.contentHeight * 0.5, native.systemFont, 20 )

textSectionA:setFillColor( 0, 0, 0 )

sceneGroup:insert( textSectionA )

–textDate

local textDate = display.newText(“Incident Date: (DD/MM/YY)”, 

175, 190, display.contentWidth, display.contentHeight * 0.5, native.systemFont, 13 )

textDate:setFillColor( 0, 0, 0 )

sceneGroup:insert( textDate )

–textBoxDay

local textBoxDay = native.newTextField( 54, 110, 75, 40 )

textBoxDay.size = 20

textBoxDay:addEventListener( “userInput”, textListener )

textBoxDay.inputType = “number”

sceneGroup:insert( textBoxDay )

–forwardSlash

local forwardSlash = display.newImage( “forwardSlash.png” )

forwardSlash:translate( 105, 110 )

sceneGroup:insert( forwardSlash )

–textBoxMonth

local textBoxMonth = native.newTextField( 156, 110, 75, 40 )

textBoxMonth.size = 20

textBoxMonth:addEventListener( “userInput”, textListener )

textBoxMonth.inputType = “number”

sceneGroup:insert( textBoxMonth )

–forwardSlash

local forwardSlash = display.newImage( “forwardSlash.png” )

forwardSlash:translate( 207, 110 )

sceneGroup:insert( forwardSlash )

–textBoxYear

local textBoxYear = native.newTextField( 258, 110, 75, 40 )

textBoxYear.size = 20

textBoxYear:addEventListener( “userInput”, textListener )

textBoxYear.inputType = “number”

sceneGroup:insert( textBoxYear )

–textTime

local textTime = display.newText(“Incident Time: (HH:MM)”, 

175, 270, display.contentWidth, display.contentHeight * 0.5, native.systemFont, 13 )

textTime:setFillColor( 0, 0, 0 )

sceneGroup:insert( textTime )

–textBoxHour

local textBoxHour = native.newTextField( 54, 190, 75, 40 )

textBoxHour.size = 20

textBoxHour:addEventListener( “userInput”, textListener )

textBoxHour.inputType = “number”

sceneGroup:insert( textBoxHour )

–semiColon

local semiColon = display.newImage( “semiColon.png” )

semiColon:translate( 105, 190 )

sceneGroup:insert( semiColon )

–textBoxMinute

local textBoxMinute = native.newTextField( 156, 190, 75, 40 )

textBoxMinute.size = 20

textBoxMinute:addEventListener( “userInput”, textListener )

textBoxMinute.inputType = “number”

sceneGroup:insert( textBoxMinute )

–Divider

local divider = display.newImage( “titleHeader.png” )

divider:translate( 160, 240 )

sceneGroup:insert( divider )

–textWasThis

local textWasThis = display.newText(“Was this an incident that caused harm?”, 

212, 422, display.contentWidth, display.contentHeight * 0.5, native.systemFont, 13 )

textWasThis:setFillColor( 0, 0, 0 )

sceneGroup:insert( textWasThis )

–textEgPer

local textEgPer = display.newText(“eg personal harm or damage to property”, 

212, 437, display.contentWidth, display.contentHeight * 0.5, native.systemFont, 11 )

textEgPer:setFillColor( 0, 0, 0 )

sceneGroup:insert( textEgPer )

–textWasThisA

local textWasThisA = display.newText(“Was this a Near Miss (No Harm)?”, 

212, 480, display.contentWidth, display.contentHeight * 0.5, native.systemFont, 13 )

textWasThisA:setFillColor( 0, 0, 0 )

sceneGroup:insert( textWasThisA )

– Image sheet options and declaration

local options = {

    width = 26,

    height = 26,

    numFrames = 2,

    sheetContentWidth = 26,

    sheetContentHeight = 52

}

local checkboxSheet = graphics.newImageSheet( “checkboxSheet.png”, options )

– Create a group for the radio button set

local radioGroup = display.newGroup()

– Create two associated radio buttons (inserted into the same display group)

local radioButton1 = widget.newSwitch

{

    left = 20,

    top = 300,

    style = “radio”,

    id = “RadioButton1”,

    width = 26,

    height = 26,

    onPress = onSwitchPress,

    sheet = checkboxSheet,

    frameOff = 1,

    frameOn = 2

}

radioGroup:insert( radioButton1 )

sceneGroup:insert( radioButton1 )

local radioButton2 = widget.newSwitch

{

    left = 20,

    top = 353,

    style = “radio”,

    id = “RadioButton2”,

    width = 26,

    height = 26,

    onPress = onSwitchPress,

    sheet = checkboxSheet,

    frameOff = 1,

    frameOn = 2

}

radioGroup:insert( radioButton2 )

sceneGroup:insert( radioButton2 )

local function OnbtnNext( event )

      if event.phase == “ended” then

            local radioOn = false

            local textFilled = true

            myData.dateDay = textBoxDay.text

            myData.dateMonth = textBoxMonth.text

            myData.dateYear = textBoxYear.text

            myData.timeHour = textBoxHour.text

            myData.timeMinute = textBoxMinute.text

            if radioButton1.isOn == true then

            myData.IRb1 = “Yes”

                  radioOn = true

          end

            if radioButton2.isOn == true then

           myData.IRb1 = “No (Near Miss)”

                  radioOn = true

            end

      if textBoxDay.text == “” or textBoxDay.text == nil or 

          textBoxMonth.text == “” or textBoxMonth.text == nil or

      textBoxYear.text == “” or textBoxYear.text == nil or

            textBoxHour.text == “” or textBoxHour.text == nil or

          textBoxMinute.text == “” or textBoxMinute.text == nil then

                  textFilled = false

           end

            if radioOn and textFilled then

                   composer.gotoScene( “incidentReportingPg3”, { effect=“slideLeft”, time=800,} )

            else

                  local msg

                  if radioOn == false and textFilled == false then

                        msg = “No input in checkbox(s) and textbox(s)”

                  else

                        if radioOn then

                              msg = “No input in textbox(s)”

                        else

                              msg = “No input in checkbox(s)”

                        end

                  end

                  local alert = native.showAlert( “Warning”, "ERROR: "…msg, { “OK” }, onComplete)

            end

       

      end

      return true

end

–btnPrevious

local btnPrevious = widget.newButton

{

   width = 150,

   height = 40,

   defaultFile = “btnPrevious.png”,

   onEvent = btnPrevious

}

btnPrevious.x = 84

btnPrevious.y = 445

–btnNext

local btnNext = widget.newButton

{

   width = 150,

   height = 40,

   defaultFile = “btnNext.png”,

   onEvent = OnbtnNext

}

btnNext.x = 235

btnNext.y = 445

–sceneGroup

sceneGroup:insert( titleHeader )

sceneGroup:insert( title )

sceneGroup:insert( textPage )

sceneGroup:insert( btnNext )

sceneGroup:insert( btnPrevious )

end 

function scene:show( event )

local sceneGroup = self.view

end

function scene:hide( event )

local sceneGroup = self.view

end

function scene:destroy( event )

local sceneGroup = self.view

end


– Listener setup

scene:addEventListener( “create”, scene )

scene:addEventListener( “show”, scene )

scene:addEventListener( “hide”, scene )

scene:addEventListener( “destroy”, scene )


return scene

[/lua]

Thanks again,

Matt.

Yeah.  I see the problem.  You didn’t follow my example completely.  You need to tell each text object how long you want it to be (maxLen) so the listener code can look it up.

For example, you have this:

--textBoxDay local textBoxDay = native.newTextField( 54, 110, 75, 40 ) textBoxDay.size = 20

but need to do this:

--textBoxDay local textBoxDay = native.newTextField( 54, 110, 75, 40 ) textBoxDay.size = 20 textBoxDay.maxLen = 2 -- Specify a maxLen field for all of your fields or my code won't work

Note: You could have debugged this by looking at the error message you got.  It surely complained about this line in the listener:

if( string.len( text ) \> maxLen ) then

Are you familiar with logcat?  If not, I strongly advice learning to use it as it will help with debugging on your Android device.

Ah I see, i’m still having issues. This time I ran it and when I selected one of my text fields sure enough I could only write two characters however, when I either deselected the text field or clicked on one of the other text fields I got a runtime error.

This time it says…

28:bad argument #1 to ‘len’ (string expected, got nil)

Any ideas here, also I’ll take a look at that logcat thanks for sharing it.

Matt.

Just verify there is something in text before operating on it:

if( text and string.len( text ) \> maxLen ) then -- aborts early if text is nil target.text = string.sub( text, 1, maxLen ) end

This is exactly what I was looking for thank you for your help.

Matt.