×
INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!
  • Students Click Here

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Students Click Here

Jobs

Access JavaSript object properties with invalid names from VFP

Access JavaSript object properties with invalid names from VFP

Access JavaSript object properties with invalid names from VFP

(OP)
I am currently working on an API involving the necessity to go through JS functions I load into a Webbrowser control, as the endpoint API is using things like postMessage JS, which need a JS eventlistener.

I can get back a JS parameter "event" and Intellisnse shows me properties and subobjects and their properties, but I get error "Unknown Name" when I access properties with uppercase letters and properties of second or deeper levels no matter how the names are composed.

I found one solution in using a JS function "flattenobject" from https://gist.github.com/penguinboy/762197 and modified this to use '_' instead of '.' and create lower case names only. That still risks one problematic case where the JS object has a property oobject.test.property and object.test_property causing a conflict when test.property is added as the already existing test_property.

Besides solving that with a more complex replacement I remember there should be an easy solution, as JS objects also can be accessed with bracket notation in JS: object.['test.property'], but doing so with the object arriving in Foxpro isn't working anymore. I've seen a case where this was about native names invalid for VFP naming conventions, but I don't find that, it would be easier than fiddling with any reworking of JS objects before returning them to VFP.

EDIT: To illustrate the problem some reprocode:

CODE

Local loJSForm, lcScript, loDocument, loScript, loText, lcJSON

loJSForm = CreateObject('jsform')

Text To lcScript NoShow
   function json2vfp(json, vfpreceiver) {
      vfpreceiver.oInbox = JSON.parse(json)
   }
EndText

loDocument = loJSForm.oWeb.Document
loScript = loDocument.createElement('script')
loScript.setAttribute('type', 'text/javascript')
loText = loDocument.createTextNode(lcScript)
loScript.appendChild(loText)
loDocument.documentElement.appendChild(loScript)

Text To lcJSON NoShow
{ "workingproperty": true,
  "nonWorkingProperty": false,
  "obj": { "notatallWorkingProperty" : false,
           "sosoworkingproperty": true
         }
}
EndText

Clear 
On Error ?? Line(), Message()
loDocument.Script.json2vfp(lcJSON, loJSForm)

Define Class jsform As Form
   Add Object oWeb As cWeb

   oInbox = .Null.

   Procedure oInbox_assign(vNewVal)
      This.oInbox = vNewVal
           
      ? 'workingproperty', vNewVal.workingproperty
      ? 'nonWorkingProperty', vNewVal.nonWorkingProperty
      ? 'obj.notatallWorkingProperty', vNewVal.obj.notatallWorkingProperty
      ? 'obj.sosoworkingproperty', vNewVal.obj.sosoworkingproperty
   Endproc
Enddefine

Define Class cWeb As OleControl
   OleClass="Shell.Explorer.2"

   Procedure Init()
      This.navigate2("about:blank")
      Do While This.oWeb.readyState<>4
         DoEvents Force
      Enddo
   Endproc

   Procedure Refresh()
      Nodefault
   Endproc
Enddefine 

To clarify: In this case, I could prevent the errors by simply defining all property names in lower case, but in the real world scenario the names of the JS properties are not in my control, they are partially native JS properties and partially added from the Restful API I use.

Also note: The 'sosoworkingproperty' can be read and is printed without error, but if you set a breakpoint in the oInbox_assign method and use intellisense to address the properties, you get obj listed when you type vNewVal., but then vNewVal.obj. is not telling you, that the sosoworkingproperty exists.

Bye, Olaf.

Olaf Doschke Software Engineering
https://www.doschke.name

RE: Access JavaSript object properties with invalid names from VFP

Hi Olaf, I came across the same issue about three years ago, and this StackOverflow thread helped me to solve partially the problem with this function:

CODE --> javascript

function namespace(object, path) {
   var result = path.split('.').reduce(function (value, index) {
        return value[index]
    }, object)
   return result;
} 

I needed array support, so I improved it and posted a working sample on that same thread:

CODE --> javascript

getProperty(obj, path) {
    return path.split(/(\[|\]|\.)/).reduce(function (x, y) {
        return ('[].'.indexOf(y) > -1) ? x : (x === Object(x) && y in x) ? x[y] : undefined;
    }, obj)
} 


this is your test using getProperty() function :

CODE -->

clear

Local loJSForm, lcScript, loDocument, loScript, loText, lcJSON

loJSForm = CreateObject('jsform')

Text To lcScript NoShow
   function json2vfp(json, vfpreceiver) {
      vfpreceiver.oInbox = JSON.parse(json)
   }

	function getProperty(obj, path) {
    return path.split(/(\[|\]|\.)/).reduce(function (x, y) {
        return ('[].'.indexOf(y) > -1) ? x : (x === Object(x) && y in x) ? x[y] : undefined;
    }, obj)
}

EndText

loDocument = loJSForm.oWeb.Document
loScript = loDocument.createElement('script')
loScript.setAttribute('type', 'text/javascript')
loText = loDocument.createTextNode(lcScript)
loScript.appendChild(loText)
loDocument.documentElement.appendChild(loScript)

Text To lcJSON NoShow
{ "workingproperty": "works",
  "nonWorkingProperty": "works too",
  "obj": { "notatallWorkingProperty" : "and this",
           "sosoworkingproperty": "and this one too"
         }
}
EndText

Clear 
On Error ?? Line(), Message()
loDocument.Script.json2vfp(lcJSON, loJSForm)

Define Class jsform As Form

   Add Object oWeb As cWeb

   oInbox = .Null.

   Procedure oInbox_assign(vNewVal)
      This.oInbox = vNewVal
           
      ? 'workingproperty', vNewVal.workingproperty
      ? 'nonWorkingProperty', vNewVal.nonWorkingProperty
      ? 'obj.notatallWorkingProperty', vNewVal.obj.notatallWorkingProperty
      ? 'obj.sosoworkingproperty', vNewVal.obj.sosoworkingproperty

? '---------------------------------------'
	? 'Using getproperty( obj, cPath ):'
? '---------------------------------------'
		js = this.oweb.document.script

      ? 'workingproperty', js.getProperty(vNewVal,"workingproperty")
      ? 'nonWorkingProperty', js.getProperty(vNewVal,"nonWorkingProperty")
      ? 'obj.notatallWorkingProperty', js.getProperty(vNewVal,"obj.notatallWorkingProperty")
      ? 'obj.sosoworkingproperty', js.getProperty(vNewVal,"obj.sosoworkingproperty")

   Endproc

Enddefine

Define Class cWeb As OleControl
   OleClass="Shell.Explorer.2"

   Procedure Init()
      This.navigate2("about:blank")
      Do While This.readyState<>4
         DoEvents Force
      Enddo
   Endproc

   Procedure Refresh()
      Nodefault
   Endproc
Enddefine 

Hope this will solve your problem too.


RE: Access JavaSript object properties with invalid names from VFP

(OP)
Thanks, Marco!

I remember something else, but this works, too.
I added the function to the object, though, so it becomes an inbuilt function I can call in VFP.

CODE

Local loJSForm, lcScript, loDocument, loScript, loText, lcJSON

loJSForm = Createobject('jsform')

Text To lcScript NoShow
   function json2vfp(json, vfpreceiver) {
      var jsobj = JSON.parse(json);

      jsobj.getproperty =
         function (path) {
            return path.split(/(\[|\]|\.)/).reduce(
               function (obj, key) {
                   return (obj === Object(obj) && key in obj) ? obj[key] : ('[].'.indexOf(key) > -1) ? obj : undefined;
               }, this)
         };
      jsobj.json = JSON.stringify(jsobj , undefined, 3);
      vfpreceiver.oInbox = jsobj;
   }
EndText

loDocument = loJSForm.oWeb.Document
loScript = loDocument.createElement('script')
loScript.setAttribute('type', 'text/javascript')
loText = loDocument.createTextNode(lcScript)
loScript.appendChild(loText)
loDocument.documentElement.appendChild(loScript)

Text  To lcJSON NoShow
{ "workingproperty": true,
  "nonWorkingProperty": true,
  "obj": { "notatallWorkingProperty" : true,
           "sosoworkingproperty": true,
           "arr": [1,2,3]
         }
}
EndText

Clear 
On Error ?? Line(), Message()
loDocument.Script.json2vfp(lcJSON, loJSForm)

Define Class jsform As Form
   Add Object oWeb As cWeb

   oInbox = .Null.

   Procedure oInbox_assign(vNewVal)
      This.oInbox = vNewVal
      ? vNewVal.json
      
      ? 'workingproperty', vNewVal.workingproperty
      ? 'nonWorkingProperty', vNewVal.nonWorkingProperty
      ? 'obj.notatallWorkingProperty', vNewVal.obj.notatallWorkingProperty
      ? 'obj.sosoworkingproperty', vNewVal.obj.sosoworkingproperty
      ? '----------------------fixed with added function-------------------'
      ? 'workingproperty', vNewVal.getproperty('workingproperty')
      ? 'nonWorkingProperty', vNewVal.getproperty('nonWorkingProperty')
      ? 'obj.notatallWorkingProperty', vNewVal.getproperty('obj.notatallWorkingProperty')
      ? 'obj.sosoworkingproperty', vNewVal.getproperty('obj.sosoworkingproperty')
      ? 'obj.arr[0]', vNewVal.getproperty('obj.arr[0]')

   Endproc
Enddefine

Define Class cWeb As OleControl
   OleClass="Shell.Explorer.2"

   Procedure Init()
      This.navigate2("about:blank")
      Do While This.readyState<>4
         DoEvents Force
      Enddo
   Endproc

   Procedure Refresh()
      Nodefault
   Endproc
Enddefine 

Bye, Olaf.

Olaf Doschke Software Engineering
https://www.doschke.name

RE: Access JavaSript object properties with invalid names from VFP

(OP)
I just thought, why not use eval()? Yes, it's evil, but it works:

CODE

...
  jsobj.getproperty =
     function (expr) { 
        return eval('this.'+expr);
     }; 

Bye, Olaf.

Olaf Doschke Software Engineering
https://www.doschke.name

RE: Access JavaSript object properties with invalid names from VFP


Eval is like you say 'evil' if you use it to run Js not totally created by you.

If you are in total control of the source I see no reason not to use it.




Marco Plaza
@nfoxProject
https://www.github.com/nftools

RE: Access JavaSript object properties with invalid names from VFP

(OP)
It's all under my control, I indeed have no worries: The whole construct is... let's say interesting. The code you have to use is doing a popup that calls an API endpoint returning a html form, which in turn returns the final result after user interaction via a window.opener.postMessage(), that comes in as event.data in an event listener from the opener window you have to program from template code only halfways documented. WEll, at least they also provide an API sandbox that you can also look into, but as it is with such APIs, the template code is too basic and the sandbox is too complex, but at least I managed to extend the template code with the sandbox to something working now.

Your nfJson library would be another choice when I'd turn event.data into JSON via JSON.stringify() and then use nfJson to turn that into a real VFP object. But this mechanism couldn't pass anything that provides methods and not just some data properties.

Bye, Olaf.

Olaf Doschke Software Engineering
https://www.doschke.name

RE: Access JavaSript object properties with invalid names from VFP

(OP)
There's just one minor issue with the getproperty function, no matter if it's the eval or your function and I guess also in general, when you suspend the receiving code and do intellisense on the function, i.e. go into the command window and type vNewVal.getproperty( VFP intellisense kicks in as it always does triggered by the opening bracket trying to get the method signature. It fails with a fatal error c0000029.

I leave this here as a warning because this could mean lost work. It's reproducable, yet the calls with expressions work even when you want to know something like the array length you can do vNewVal.getproperty('obj.arr.length'), that's working with eval.

So instead of discovering object properties with intelllisense, you better make use of the json property I added to get an overview of the object schema and available property names.

I wonder if this has to do with the anonymous nature of the function and if the getproperty function can be added to the jsobj so VFPs intellisense does not error. I guess it fails as you can't define parameter types. But it's only an intellisense problem, as said. The getproperty function doesn't even error on undefined properties, it only returns null, in your code you've forseen this with 'undefined', but this also comes back when you use eval('this.'+expr), so overall this is stable at runtime.

Bye, Olaf.

Olaf Doschke Software Engineering
https://www.doschke.name

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members!

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close