How to add a property to a map dynamically in velocity? - dictionary

I have the following code
$pageName = "test";
$Container = {};
I like to set a property of $Container by a variable. I tried $Container.set("test", $pageName);. It didn't raise any errors, but $Container.test or $Container.get("test"); display nothing.
How do I fix it?

The problem is that set is the wrong method. You need to do a put. Remember - Velocity is calling the Java methods. There is no "set" method on a Map object.
Specifically, you can do
$Container.put("test", $pageName)
Now, one weird thing is that this will print "true" or "false" in the page, since the Map.put() method returns a boolean. So I always do
#set($dummy = $Container.put("test", $pageName))
which does the put and stores the result in another reference (which you can then ignore) instead of rendering it to the page.

Hey I ran into the same problem is the "true" or "false" printed on the page, and there is a simpler way to handle it. What I did is a little weird, and I did it Confluence, which of course uses Velocity under the covers. I mention that because I understand Velocity can be used in may different applications.
With a Confluence user macro, I check for a previously created attribute on the req variable, the request variable, i.e. "myPageVars". Then I use the put method to put a new key-value pair, based on the macro parameters. By using the $! prefix, rather than just $, the output isn't sent to the screen.
...
$!req.getAttribute("myPageVars").put( $paramKey, $paramValue )
...
I'm somewhat new to Velocity, so I can't guarantee this will work in every context, but it seems syntactically easier than the whole #set ($dummy etc. line.

Related

Meteor reactive-var package is missing the equals() method, is this a bug?

I'm learning about reactive programming in Meteor:
https://stephenwalther.com/archive/2014/12/05/dont-do-react-understanding-meteor-reactive-programming
I believe that the idea behind Session.equals(key, value) is to remember an association between the reactive variable and the desired value so that updates only propagate to the surrounding code if the equality changes. That way if we have hundreds of views that depend on the variable, only the old and new views get their update code triggered when the value changes.
Note that this would not be the case if we called Session.get(key) === value because every view's code would be called when the variable changes. This is discussed further under the Session.get versus Session.equals() section of the article.
But I found an inconsistency under the Using Reactive Variables section where it says:
Notice that a reactive variable, unlike the Session object, does not have an equals() method. Yes, that is a shame.
So reactive-var is missing equals() but reactive-dict has ReactiveDict.equals().
I can't really see a conceptual reason to exclude ReactiveVar.equals(). Maybe they had no context for storing the association, or maybe there is some scoping or other issue with Javascript that prevents this that I don't fully understand.
So my question is: is this a bug?
Should I just always use reactive-dict? In which case I would change everything from:
let myReactiveVar = new ReactiveVar();
...
if(myReactiveVar.get() === 'myValue')
To the more verbose (but performant):
let myReactiveDict = new ReactiveDict();
...
if(myReactiveDict.equals('myReactiveVar', 'myValue'))
Which would match the functionality provided by Session.equals().
Another option would be to extend the ReactiveVar prototype with my own equals() method or inherit it in a child class and provide a MyReactiveVar.equals() method. Kudos if someone can provide examples to do either of these workarounds that we could submit as a pull request to the Meteor maintainers.
Update: I forgot to mention that ReactiveVar does take an equalsFunc optional parameter in its constructor. It might be possible to hack that as a reactive code block to partially implement equals() functionality without extending the class. Also, here is a related issue on GitHub.
Update: to save time, here is the relevant source code for ReactiveVar and ReactiveDict.equals(). I believe that the value parameter gets converted to serializedValue and is then added as a dependency in ReactiveDict, but I still don't see why it wouldn't be possible to do something similar for ReactiveVar.
The reason there's no equals method for ReactiveVar is because set only invalidates the computations is the new value differs from the current value.
Sets the current value of the ReactiveVar, invalidating the Computations that called get if newValue is different from the old value.
const example = new ReactiveVar(0);
Tracker.autorun(() => {
console.log(example.get());
});
example.set(1); // logs 1
example.set(0); // logs 0
example.set(0); // doesn't log
This is similar behaviour to ReactiveDict's equals method.
Note that set on ReactiveDict does not behave this way. Calling set broadcasts that the value has changed. If you want to prevent the computation from invalidating, that is when you would use equals.
Set a value for a key in the ReactiveDict. Notify any listeners that the value has changed (eg: redraw templates, and rerun any Tracker.autorun computations, that called ReactiveDict.get on this key.)

Google Tag Manager - Parse Dynamic Data Layer Variable

I want to parse a 'pushed' data layer string. I intend to use it to track click events and setup the appropiate funnels in Google Analytics, it looks as follows: products.view.19|view recent product|19
The first part (products.view.19) is the unique page identifier.
The second part (view recent product) is the action.
The last part is (19) is the action identifier, this way actions may be grouped and compared more easily.
So I did the following, I first created a trigger (it fires when a link has the tag 'data-trackclick' in it) which pushes the data value to a variable (variable for datalayer). However, now I want to split that variable in to 3 new variables, as described above. I selected 'javascript macro' for this but somehow it returns 'undefined'. The macro looks as follows:
function() {
var data = {{TrackClickData}};
var pieces = data.split('|');
if (pieces[0].length()) {
return pieces[0];
} else {
return data;
}
}
Obviously this didnt work since it would only run on the initial load and not (like I thought) when the macro was requested, so it should somehow be fired on the 'click' and then set the variables accordingly.
Is this possible to do? Or do I really have to add the dataLayer.push() in script tags?
A few things:
.length() is wrong, the property for array length is .length without the ()
if it exists, pieces[0] is not an array, then .length would return the string length, see How do you check for an empty string in JavaScript? for more standard way of checking for empty strings
Is this possible to do? There's virtually nothing you can't do with GTM, since you can write JavaScript code, you can do whathever you code allows you to do, and splitting a string to use parts of it as variables is certainly within the realm of possibilities.
My advise is to make your code work outside GTM first (eg test it in the browser console), then once it's all working, port it to GTM.

Meteor local package array returns empty on method call

I have a local package with the following code
#articleSubmitMethodCallbacks = []
articleSubmitMethodCallbacks.push(addThumbnailOnSubmit)
This works and returns an array with a function in.
Then I have a method called articleInsert
In that method I have the following code
article = articleSubmitMethodCallbacks.reduce(((result,currentFunction)->
return currentFunction (result)
), article)
Now for some reason, every time I call this method, articleSubmitMethodCallbacks stays an empty array, even though before it ran it has the function in it. It somehow gets reset, any idea why this happens?
Okay strange answer but here it goes, apparently it has something to do with the naming articleSubmitMethodCallbacks that interferes with something inside Meteor.
If I use any other array name, it works perfect. To be clear I didn't overwrite articleSubmitMethodCallbacks anywhere and in fact the code above was the only reference to it in the whole project.

JavaFX binding and null values

I was wondering how to bind values where the source of the bind could be null.
I have a property:
private ObjectProperty<Operation> operation = new SimpleObjectProperty<>(null);
I also have a text field:
#FXML
private Text txtCurrentOperation;
I would like to bind the textProperty of the field to the value of the operation object.
My first thought was to use FluentAPI with its when/then/otherwise construct, but it is eagerly evaluated so the solution:
Bindings.when(operation.isNotNull())
.then("null")
.otherwise(operation.get().getName()));
will throw a NPE, because the parameter of otherwise is evaluated no matter what the result of the when.
My next idea was to use lambda somehow:
txtCurrentOperation.textProperty().bind(() ->
new SimpleStringProperty(
operation.isNotNull().get() ? "Null" : operation.get().getName()
));
But the bind has no lambda enabled solution. (Later I realized that it couldn't have, becasue the real work goes backward: the change of the binded object (operation) will trigger the update of the binder (the field text property).)
Some articles I found suggested to use an "extremal" value for the property instead of null. But Operation is a complex and heavy weight component so it is not trivial to construct an artifical instance to represent null. Even more, this seems to me boilercode, something the binding mechanism is designed to help eliminating.
My next try was to logically swap the binding direction and add listener to the operation property and let it update the field programatically. It works and rather simple as long as the need of update only depends the operation object instances:
operation.addListener((e) -> {
txtCurrentOperation.setText(operation.isNull().get() ?
"Null" : operation.get().getName());
});
operation.set(oper);
It is relatively simple, but doesn't work: it throws "A bound value cannot be set." exception and I don't see why is the text property of the control regarded as bound.
I ran out of ideas. After much searching, I still cannot solve the simple problem to update a text field differently based on whether the source is null or not.
This seems so simple and everyday problem, that I am sure I missed the solution.
If a 3rd party library is an option, check out EasyBind. Try something like this:
EasyBind.select(operation)
.selectObject(Operation::nameProperty)
.orElse("null");
There's also a JavaFX JIRA issue for the type of functionality provided by EasyBind. If you don't want to use a 3rd party library, try Bindings.select:
Bindings.when(operation.isNotNull())
.then("null")
.otherwise(Bindings.select(operation, "name"));
Be aware the null checking in Bindings.select isn't super efficient. There's a JIRA issue for it.
Just in case if somebody using not Java itself but Kotlin.
It is a good idea to use wonderful tornadofx library.
There you can just use operation.select{it.name}. Although, this feature seems not to be documented yet, so it took some time to discover it.

How to read xml tags and its data using flex?

I need to read xml tags and its datas from one file and then write it to another xml..how to do it?? please let me know immediately...?
See http://livedocs.adobe.com/flex/2/langref/XML.html . I find it hard to believe you googled this before asking.
You can use the FileReference.save() method to save XML data to a local file. It will prompt the user for a location to save the file first and then save the data.
Here's an example:
var xml:XML = <root><someXmlTag/></root>;
var fileReference:FileReference = new FileReference()
fileReference.save(xml, "myfile.xml");
As far as I knew, Flex wasn't able to write to files!
I use a HTTPService to load the XML file and a result even handler to access it.
<mx:HTTPService id="service" url="myXml.xml" result="ServiceResult (event)"/>
Do not specify a result format in the HTTPService tag.
This is the code for the result event handler.
private function ServiceResult (e : ResultEvent) : void {
e.result.XmlTag.AnotherXmlTag;
}
You can also use service.lastResult to access the last result returned by the HTTPService. The result is fully compatible with the dataProvider property, especially in arrays and chart series.
var series : LineSeries = new LineSeries ();
series.dataProvider = e.result.XmlTag.AnotherXmlTag;
This will take the value in all AnotherXmlTag tags within XmlTag. For series, though, you should also specify either a yField or and xField, but it digress :-)
If it doesn't work, you can also cast it using the as keyword, example:
series.dataProvider = e.result.XmlTag as ArrayCollection;
I haven't actually tried casting it in this scenario, but the bottom line is that XML tags are vary compatible with arrays and ArrayCollections.
In your case, you would just use e.result to get the complete XML file, assign it to a variable, and write it using Ben's method. You can also create an array from individual values using the way I explained above, and manually insert tags and such if you need. The advantage of this is that you have all the values ready in an array would you need them later on. If you loop through the indices, this won't require a lot of work, and it would be the way I'd do it.
Hope this helps!

Resources