How to Get and Set KM Variables from JXA?

###How to Get and Set KM Variables from JXA?
I checked the wiki, and although there is a page for JXA, it is empty.

The following JXA function, kmVar(k), published numerous times by @ComplexPoint, doesn’t seem to work. Running it results in Script Editor becoming hung, and requires a force quit:

function kmVar(k) {
		var kme = Application("Keyboard Maestro Engine"),
			vs = kme.variables,
			vks = vs.where({name:k});
				
		return vks.length ? vks[0] :
			vs.push(kme.Variable({'name': k})) && vs[k];
	}
	
var oKMVar = kmVar("BrowserTitle")
oKMVar

The code in @ComplexPoint’s GitHub has the same problem:
Example: accessing Keyboard Maestro variables from Yosemite JXA Javascript for Applications

“BrowserTitle” is a valid and existing KM variable in my account.

Getting the same KM var works fine in AppleScript:

--------------------------------------------------------------
tell application "Keyboard Maestro Engine"
	set strKMVar to value of variable "BrowserTitle"
end tell -- application "Keyboard Maestro Engine"
--------------------------------------------------------------

log strKMVar

Has something changed? Am I doing something wrong?

I’m running KM 7.0.2 in Yosemite 10.10.5.
I’ve tried a Mac reboot, but still have the same problem.

Hey JM,

Here’s a working GET on 10.11.2 (variable must exist).

function run() {
 
   var strKMVarName = "myKMVariable";
   var kmVarRef
 
   // Get a reference to a Keyboard Maestro variable (existing or new)
   function kmVar(k) {
      var kme = Application("Keyboard Maestro Engine"),
         vs = kme.variables,
         vks = vs.where({name:k});
            
      return vks.length ? vks[0] :
         vs.push(kme.Variable({'name': k}));
   }
 
   // GET A REFERENCE TO A KM VARIABLE BY NAME
   kmVarRef = kmVar(strKMVarName);

   // RETURN VALUE OF REFERENCED KM VARIABLE
   return kmVarRef.value();
}

At the moment I don’t have time to analyze it and figure it out completely.

I do think more descriptive variable names would enhance the readability of the script.

-Chris

Thanks, Chris.

But I think this will create the KM var if it does not exist:

I think the push() adds the requested var to the KM var list, thus creating it.
But I'm not sure. Haven't tested it.

Chris, this one also hangs if you give it a KM var that doesn't exist, and try to run it several times.

I seem to be on a roll of answering my own questions. I hope you guys find this helpful.

After a lot of searching, coding, & testing, I put together these two functions, adapted from some earlier code published by @ComplexPoint:

  1. setKMVar(pstrName, pstrValue)
  • Sets the value of the KM variable, and creates it if needed
    • Notification made if variable is created.
  1. getKMVar(pstrName)
    • GETs the value of the KM variable
    • Shows error alert if variable is not found

Please post if you see any bugs or issues, or have suggestions for improvement.
I have done some testing, but they need more.
I can say that at no time did either of these functions cause Script Editor to hang.

//	--- STUB TO TEST FUNCTIONS ---

setKMVar("ASName", "Name Set from JXA") // check your KM Prefs > Variables to confirm
console.log( getKMVar("BrowserTitle"))


//=====================================================================	
function setKMVar(pstrName, pstrValue) {
//=====================================================================	

	var app = Application.currentApplication()
	app.includeStandardAdditions = true

	var appKM = Application("Keyboard Maestro Engine")
		
	var oVars = appKM.variables
		
	try {
		oVars[pstrName].name();
		
	} catch (e) {
		appKM.variables.push(appKM.Variable({'name': pstrName	}));
		
		app.displayNotification(
			pstrName, 
			{
				withTitle: "Set KM Variable",
				subtitle:  "Variable was Created",
				soundName: "Basso"
		  });

		}	// END try/catch
		
		oVars[pstrName].value = pstrValue
		
		return
		
}	// END function setKMVar
//–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

//=====================================================================	
function getKMVar(pstrName) {
//=====================================================================	

	var app = Application.currentApplication()
	app.includeStandardAdditions = true

	var appKM = Application("Keyboard Maestro Engine")
		
	var oVars = appKM.variables
		
	try {
		var strValue = oVars[pstrName].value();
		
	} catch (e) {
		
		strValue = undefined
		
		app.beep()
		var oAns = app.displayAlert('KM Variable does NOT exist', {
				message: 'Var Name: ' + pstrName,
				as: 'critical'
			})

		}	// END try/catch
				
		return strValue
		
}	// END function getKMVar
//–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

//============================ END OF FUNCTIONS ====================

Has something changed? Am I doing something wrong?

Possibly : - )

This is working fine here (copy-pasted from your post, with .value() appended in the final line, to get a value rather than a reference.

function kmVar(k) {
		var kme = Application("Keyboard Maestro Engine"),
			vs = kme.variables,
			vks = vs.where({name:k});
				
		return vks.length ? vks[0] :
			vs.push(kme.Variable({'name': k})) && vs[k];
	}
	
var oKMVar = kmVar("BrowserTitle")
oKMVar.value()

I am running OS X 10.11.2

(I presume that you have set the language selector at top right of Script Editor to JavaScript rather than AppleScript ?)

Just tried it again, with a copy/paste from your above post, and same results: Script Editor locks up.

Really? Sort of a dumb question, isn't it? Script won't compile or run unless you have the right language. So how could SE lock up if it doesn't run?

Everything else runs fine, including the new functions I posted.

Something strange that it works for you, but not me (and I've tried it on two Macs, but with sync'd macros.

I'm running Yosemite 10.10.5, and you're running El Capitan, right? Could that be a factor?

Sort of a dumb question, isn't it ?

No, I don't think so – foolish to take anything for granted in dealings with computers – the damnedest things trip all of us up.

Good luck !

You forgot to ask if I had my Mac plugged in, and the power on. :astonished:

IAC, I'm not trying to debug your code at this point, since the functions I posted are working very well.

You forgot to ask if I had my Mac plugged in, and the power on

You are absolutely right – I should have asked.

(That question resolved 30% of technical calls in the early days of the IBM PC : - )