I'm attempting to write a Meteor package which can be placed inside templates. So I first attempted to register a helper.
Template.registerHelper('testHelper', function(a, b) {
console.log(a);
console.log(b);
})
I've added the package inside /packages, and in my client template, when I added {{testHelper "hello" "meow"}}, the console logged hello and meow, which is what I expected.
When I added {{testHelper "hello"}}, I expected the console to log hello and null, since nothing was passed as the second parameter. But instead it returned hello and an object - Spacebars.kw {hash: Object}
What is this Spacebars.kw {hash: Object}? What can I do if I want it to return null instead?
Spacebars.kw contains a hash object that has a hash of input parameters.
Meteor has two methods to match up methods, one is direct matching which is where the parameters are directly input, e.g {{testHelper "variable1" "variable2" "variable3"}}, would match up as function(a,b,c) as variables 1-3 matching up to a,b and c respectively.
The second method of input is using a hash:
{{testHelper a="variable1" b="variable2" c="variable3"}}
This would give a single parameter to function(a) where a is a Spacebars.kw object.
The Spacebars.kw object would have a subobject called hash with a structure that matches:
{ "a" : "variable1",
"b" : "variable2",
"c" : "variable3" }
Meteor will attempt to match up the first param directly, but the subsequent parameters will be matched up as hashes incase the second input is empty such as in the case where you use {{testHelper 'hello'}} where b would be null, so it's given as the hash instead.
Its generically given as this, so if you get b as a Spacebars.kw object, you can assume there was no second input. The alternative is you could use the hash style declarations and then directly check if the hash value is null:
{{testHelper text="Hello"}}
{{testHelper text="Hello" othertext="Hellooo"}}
and the helper:
Template.registerHelper('testHelper', function(kw) {
console.log(kw.hash.text);
console.log(kw.hash.othertext);
});
Related
Swiftui dictionaries have the feature that the value returned by using key access is always of type "optional". For example, a dictionary that has type String keys and type String values is tricky to access because each returned value is of type optional.
An obvious need is to assign x=myDictionary[key] where you are trying to get the String of the dictionary "value" into the String variable x.
Well this is tricky because the String value is always returned as an Optional String, usually identified as type String?.
So how is it possible to convert the String?-type value returned by the dictionary access into a plain String-type that can be assigned to a plain String-type variable?
I guess the problem is that there is no way to know for sure that there exists a dictionary value for the key. The key used to access the dictionary could be anything so somehow you have to deal with that.
As described in #jnpdx answer to this SO question (How do you assign a String?-type object to a String-type variable?), there are at least three ways to convert a String? to a String:
import SwiftUI
var x: Double? = 6.0
var a = 2.0
if x != nil {
a = x!
}
if let b = x {
a = x!
}
a = x ?? 0.0
Two key concepts:
Check the optional to see if it is nil
if the optional is not equal to nil, then go ahead
In the first method above, "if x != nil" explicitly checks to make sure x is not nil be fore the closure is executed.
In the second method above, "if let a = b" will execute the closure as long as b is not equal to nil.
In the third method above, the "nil-coalescing" operator ?? is employed. If x=nil, then the default value after ?? is assigned to a.
The above code will run in a playground.
Besides the three methods above, there is at least one other method using "guard let" but I am uncertain of the syntax.
I believe that the three above methods also apply to variables other than String? and String.
I’ve a handlebar expression which is giving me a dynamic string. I want to remove the white space between letters and use it as a div id. I know I can do this using JS. But is there a way to do this within handlebar template?
{{name}} is giving me “abc xyz” and I want “abcxyz” string.
What you can do is register a helper yourself and use it in your template to replace the white-space in the string with nothing.
Handlebars.js has a function registerHelper(String, Function) which (as you see) takes a string (the name of your helper) and a function that will return the result of your helper.
For example, if we want a helper function that replaces "Facebook" with "Google" in a given string you could do something like this.
Handlebars.registerHelper('replace', function(string) {
return string.replace('Facebook', 'Google');
});
In the template we would invoke it like {{replace "Hello, Facebook!"}} and it would return Hello, Google!.
In case of a multipurpose function (what it obviously should be in this case instead of the example I gave) you would pass the string to invoke the replacement on, the string to replace and what it should be replaced with.
Handlebars.registerHelper('replace', function(string, search, replace) {
return string.replace(search, replace);
});
In the same way as we did before we would invoke it in the template using {{replace "Hello, Facebook!" "Facebook" "Google"}}.
If you want to avoid writing your own helpers. You can use the following module : https://github.com/helpers/handlebars-helpers
simply install it
npm install --save handlebars-helpers
And you're good to go, you can use the following helper for your issue :
{{replace name " " ""}}
Here's another usage example :
{{replace "a b a b a b" "a" "z"}}
<!-- results in: 'z b z b z b' -->
I have incoming param List<Somedata>.Somedata class contains id field.
My goal is to make HashMap<Somedata.id, Somedata> from this list.
Is next approach correct or there is a better/safer way to do that?
list
.filter { it.id != null }
.associateTo(HashMap(), {it.id!! to it})
Actually, I cannot understand, why should I use !! keyword in associateTo method, when above I filtered it with non-null values only.
Or maybe there is a good way to perform this with ?. or ?.let keywords?
You can do:
list.mapNotNull { e -> e.id?.let { it to e } }.toMap()
Breakdown:
The call to .let with the ?. safe call operator will make the result null if the element is null.
So the lambda passed to mapNotNull is of type (Somedata) -> Pair<IdType, Somedata>.
mapNotNull discards the null pairs, and toMap turns the resulting List<Pair<IdType, Somedata>> into a Map<IdType, Somedata>.
If you want to avoid the creation of an intermediate list to hold the pairs, you can turn the list into a lazy Sequence from the start:
list.asSequence().mapNotNull { e -> e.id?.let { it to e } }.toMap()
Alternatively, since you asked:
why should I use !! keyword in associateTo method, when above I filtered it with non-null values only.
this is because the list is still of type List<Somedata> - this says nothing about the nullability of the field itself. The compiler does not know that the id fields are still not null, by the time your associateTo call is executed.
I want to see if a variable exists - i.e. that I have created in.
if(exists(this.mydict))
{ //append my dict
}else
{
// initialize dict
}
Trouble is this fails on
Error in exists(this.mydict)
What am I doing wrong?
How can I extend the exists function to work with the following:
Any ideas how I would extend to this to looking at seeing whether a nested dictionary would also exist. I.e. for example: if(exists("mylists[[index]]['TSI']")), where the mylists object is a dictionary look up that also wants to contain a nested dictionary.
exists() function takes a character argument with the variable name:
if(exists("this.mydict")){
# you can use this.mydict here
}else{
# initialize this.mydict
# e.g. this.mydict <- "some value here"
}
Here is the definition of my Package class:
type Package ([<ParamArray>] info : Object[]) =
do
info |> Array.iter (Console.WriteLine)
member this.Count = info.Length
and here is the IL, I'm trying:
let ilGen = methodbuild.GetILGenerator()
ilGen.Emit(OpCodes.Ldstr, "This is 1")
ilGen.Emit(OpCodes.Ldstr, "Two")
ilGen.Emit(OpCodes.Ldstr, "Three")
ilGen.Emit(OpCodes.Newobj, typeof<Package>.GetConstructor([|typeof<Object[]>|]))
ilGen.Emit(OpCodes.Ret)
but this doesn't seem to work. I tried:
ilGen.Emit(OpCodes.Newobj, typeof<Package>.GetConstructor([|typeof<String>; typeof<String>; typeof<String>|]))
a well as:
ilGen.Emit(OpCodes.Newobj, typeof<Package>.GetConstructor([|typeof<Object>; typeof<Object>; typeof<Object>|]))
but it just laughs at me. What am I doing wrong?
The [<ParamArray>] attribute indicates to a compiler that a method accepts a variable number of arguments. However, the CLR doesn't really support varargs methods -- it's just syntactic sugar provided by the C#/VB.NET/F# compilers.
Now, if you take away the [<ParamArray>], what are you left with?
(info : Object[])
That is the signature of the constructor you're trying to call.
So, you'll need to use the newarr and stelem opcodes to create an array, store the values into it, then call the constructor using the array as the argument. This should do what you want (though I haven't tested it):
let ilGen = methodbuild.GetILGenerator()
// Create the array
ilGen.Emit(OpCodes.Ldc_I4_3)
ilGen.Emit(OpCodes.Newarr, typeof<obj>)
// Store the first array element
ilGen.Emit(OpCodes.Dup)
ilGen.Emit(OpCodes.Ldc_I4_0)
ilGen.Emit(OpCodes.Ldstr, "This is 1")
ilGen.Emit(OpCodes.Stelem_Ref)
// Store the second array element
ilGen.Emit(OpCodes.Dup)
ilGen.Emit(OpCodes.Ldc_I4_1)
ilGen.Emit(OpCodes.Ldstr, "Two")
ilGen.Emit(OpCodes.Stelem_Ref)
// Store the third array element
ilGen.Emit(OpCodes.Dup)
ilGen.Emit(OpCodes.Ldc_I4_2)
ilGen.Emit(OpCodes.Ldstr, "Three")
ilGen.Emit(OpCodes.Stelem_Ref)
// Call the constructor
ilGen.Emit(OpCodes.Newobj, typeof<Package>.GetConstructor([|typeof<Object[]>|]))
ilGen.Emit(OpCodes.Ret)
NOTE: In this code, I used the dup OpCode to avoid creating a local variable to hold the array reference while storing the element values. This is only feasible because this code is fairly straightforward -- I strongly suggest you create a local variable to hold the array reference if you want to build something more complicated.