I need to pass data between views in my client-server app. For simple string value, I can put them as attributes on the target element and read the value when the select event is triggered on it. From there, I can pass this string value onto the next document pretty easily.
But the problem comes with much more complex data that's in JSON format. I tried doing JSON.stringify(myData) and putting this value in an attribute. But the compiler doesn't like the { in this attribute value.
I could probably try escaping all the different characters that the compiler has problems with. But I don't think that's a good idea.
Is there any way of implementing jQuery's .data() functionality in TVML and TVJS ? Or is there any other way that makes sending data between views a possibility ?
You can pass your data as URL parameters. Then in the new view, get them using Javascript.
EDIT: And I see in the comment above you came to a similar conclusion.
You could keep your data in a semi-global associative array. Store the key in an attribute on the element and use that to get your data structure.
Ex:
var globalData;
function onSelect(e){
var id=e.target.getAttribute("id");
var specificData=globalData[id];
}
Related
I have a Typescript app. I use the localstorage for development purpose to store my objects and I have the problem at the deserialization.
I have an object meeting of type MeetingModel:
export interface MeetingModel {
date: moment.Moment; // from the library momentjs
}
I store this object in the localStorage using JSON.stringify(meeting).
I suppose that stringify call moment.toJson(), that returns an iso string, hence the value stored is: {"date":"2016-12-26T15:03:54.586Z"}.
When I retrieve this object, I do:
const stored = window.localStorage.getItem("meeting");
const meeting: MeetingModel = JSON.parse(stored);
The problem is: meeting.date contains a string instead of a moment !
So, first I'm wondering why TypeScript let this happen ? Why can I assign a string value instead of a Moment and the compiler agree ?
Second, how can I restore my objects from plain JSON objects (aka strings) into Typescript types ?
I can create a factory of course, but when my object database will grow up it will be a pain in the *** to do all this work.
Maybe there is a solution for better storing in the local storage in the first place?
Thank you
1) TypeScript is optionally typed. That means there are ways around the strictness of the type system. The any type allows you to do dynamic typing. This can come in very handy if you know what you are doing, but of course you can also shoot yourself in the foot.
This code will compile:
var x: string = <any> 1;
What is happening here is that the number 1 is casted to any, which to TypeScript means it will just assume you as a developer know what it is and how you to use it. Since the any type is then assigned to a string TypeScript is absolutely fine with it, even though you are likely to get errors during run-time, just like when you make a mistake when coding JavaScript.
Of course this is by design. TypeScript types only exist during compile time. What kind of string you put in JSON.parse is unknowable to TypeScript, because the input string only exists during run-time and can be anything. Hence the any type. TypeScript does offer so-called type guards. Type guards are bits of code that are understood during compile-time as well as run-time, but that is beyond the scope of your question (Google it if you're interested).
2) Serializing and deserializing data is usually not as simple as calling JSON.stringify and JSON.parse. Most type information is lost to JSON and typically the way you want to store objects (in memory) during run-time is very different from the way you want to store them for transfer or storage (in memory, on disk, or any other medium). For instance, during run-time you might need lookup tables, user/session state, private fields, library specific properties, while in storage you might want version numbers, timestamps, metadata, different types of normalization, etc. You can JSON.stringify anything you want in JavaScript land, but that does necessarily mean it is a good idea. You might want to design how you actually store data. For example, an iso string looks pretty, but takes a lot of bytes. If you have just a few that does not matter, but when you are transferring millions a second you might want to consider another format.
My advise to you would be to define interfaces for the objects you want to save and like moment create a .toJson method on your model object, which will return the DTO (Data Transfer Object) that you can simply serialize with JSON.stringify. Then on the way back you cast the any output of JSON.parse to your DTO and then convert it back to your model with a factory function or constructor of your creation. That might seem like a lot of boilerplate, but in my experience it is totally worth it, because now you are in control of what gets stored and that gives you a lot of flexility to change your model without getting deserialization problems.
Good luck!
You could use the reviver feature of JSON.parse to convert the string back to a moment:
JSON.parse(input, (key, value) => {
if (key == "date") {
return parseStringAsMoment(value);
} else {
return value;
});
Check browser support for reviver, though, as it's not the same as basic JSON.parse
I get json in stream and try to replace value of one field in payload.
transform --expression=payload.replaceAll() does not fit my needs as it treat payload as String.
I think of such operation
transform --expression=#jsonPath(payload,'$.result.grupy[*].lp')='new_value'
but it does not perform this assigment. How construct SPEL/JsonPath expression to set new value?
I need something like payload.setField('lp','new_value')
It's not possible to do that; you would need a custom processor module, or a custom SpEL function, to make changes like that.
The #jsonPath function simply returns an element from the JSON.
Not sure why payload.replace() expression doesn't fit your requirements, but the #jsonPath() SpEL-fuction is for extraction the data from JSON, not for modification.
From other side you misunderstood a bit a concept of transformer component. It returns a new object, but doesn't modify the request.
To achieve your requirements you should take a look to the Content Enricher, which exactly is intended to modify the incoming payload and return it as a reply.
To simplify your life you should take a look to the <int:object-to-map-transformer> to have ability to change field from the next <int:enricher> component.
Right, for this purpose you should write your own processor module.
So I've read that you cannot expect a default order when requesting json. I've seen this in action making a call to a little api that I built, that will return a jumbled, random order of elements each time I make a different call.
How does a site like ticketfly's api ( call it here http://www.ticketfly.com/api/events/upcoming.json?venueId=57 ) always ensure that the json returned is in a specific order?
The event ids always first, etc.
Thanks for shedding some light on the situation.
If you are in control of the endpoint API then you can hardcode the order in which you render the properties. Though I have to ask why exactly do you need the JSON properties in a particular order? You will finally be accessing the properties via there property names so the order in which they appear in the JSON should not ideally matter.
EDIT : Since your bosses insist on this (what can one say now?):
You can try and see if any of the following suits your needs:
Try hardcoding the display order in the view's representation. This means you will need to echo/print each property name explicitly in the view script. In PHP it could be something like echo $variable_representing_json["id"]; and so forth. Note that with this approach you needn't change the original JSON representation.
If you want the original JSON representation to be changed then depending on how you are doing the process it varies in difficulty:
If it's string concatenation that you are using to represent the json then hard-code the order in which the json properties get concatenated in the string.
In some languages the display order of properties is actually a representation of the order in which the properties were defined. In simple words if $var is an empty json representation then you should define $var["id"] = {some_val} first to display it first.
If you are using a framework for processing the JSON data it may have its own quirks irrespective of how you define your representation. In such cases you will have to try and see if you can work around the issue or if it gives any helper methods.
I have no idea how to handle this in ColdFusion 9, I have a form being submitted (POST) with element checkboxes, called items[].
When I do a <cfdump var="#form#" /> no-problem, I get all the items shown with the proper names like items[] eg:
struct
ITEMS[] 13,14
FIELDNAMES ITEMS[]
however doing a <cfdump var="#form.items[]#" /> results in an error. How do I access the CF9 field values? Somehow loop through it?
I cannot seem to do anything with the array to get the id's out of it? Thoughts? I'm kind of stumped and ColdFusion isn't the easiest language to find examples / references on the net. ;)
Is there a correct way to deal with this? I need to get the ID's out of there so I can reference what lines were checked in the form, so I can follow up with an action.
Thanks!
There's no Form Array’s in ColdFusion. Having '[]' at the end doesn't make it an array. You can access the checkbox values from form scope like this:
FORM["ITEMS[]"]
Dot notation doesn't work 'cause of the '[]'. See: http://help.adobe.com/en_US/ColdFusion/9.0/Developing/WSc3ff6d0ea77859461172e0811cbec22c24-7fb2.html
Values from checkboxes are just comma separated values, which is a List in ColdFusion
To loop through it, use cfloop list=:
<cfoutput>
<cfloop index="i" list="#FORM['ITEMS[]']#">
#i#
</cfloop>
</cfoutput>
To convert a list to array, use ListToArray(). There are list functions like listGetAt(), but if you're doing lots of random access, it'd be smarter to convert the list into an array first.
Thoughts, I'm kindof stumped and
coldfusion isn't the easiest language
to find examples / references on the
net ;)
http://help.adobe.com/en_US/ColdFusion/9.0/Developing/index.html
http://learncf.com/tutorials
http://www.easycfm.com/
http://www.carehart.org/ugtv/
I can highly recommend Brian Kotek's "Form Utils" for cases such as this: http://www.briankotek.com/blog/index.cfm/2007/9/4/Implicit-Creation-of-Arrays-and-Structures-from-Form-Fields
I use this in every app I build, because working with arrays and structs on the form submission side is much more preferable to working with lists, imo.
See also the second answer here. It describes how to retrieve values from a field with multiple instances on a form as an array. I have to say though, I've been working in CFML for many years, and I've yet to do this myself, or see it done in any app I've worked on. I think that's just because avoiding commas is very much simpler, but if you can't or don't want to work around it that way, it is possible.
Also, note that in an ajax world, if you json encode the entire body of a post request, rather than individual form fields, it can be any arbitrary data structure, retrievable easily on the server. The snippet below shows how to get to it from ColdFusion. I'm not certain about other languages, but it's almost certainly possible.
To send a post like that using jQuery, JSON.stringify your data before passing it to jQuery, as noted here and here.
If you're building your own ajax request, the punchline would be:
xhr.send(JSON.stringify(data));
To access that data on the server side, this ColdFusion example looks first for that kind json-encoded post body, then a post with json data in the form field 'input', then in a url field with that same name. In all cases, the resulting data gets deserialized and assigned to the local var 'input', which you can then put in request scope, 'rc', or whatever your code expects.
if (Find('application/json', cgi.content_type))
{
input = ToString(GetHttpRequestData().content);
if (IsJSON(input))
input = DeserializeJSON(input);
}
else if (StructKeyExists(form, 'input') and IsJSON(form.input))
input = DeserializeJSON(form.input);
else if (StructKeyExists(url, 'input') and IsJSON(url.input))
input = DeserializeJSON(url.input);
With you list that are Id's it works fine, but if you have an array with comma's in then you're stuck.
In that case you can use the Java method getParameterValues.
<cfdump var="#getPageContext().getRequest().getParameterValues('ITEMS')#">
This will give you an standard CF array which you can use.
For ColdFusion 10+, if you use the sameformfieldsasarray setting in your Application.cfc like this:
component {
this.name = "testingzone2c";
this.sameformfieldsasarray=true;
}
You will get an actual array of form fields with the same name.
ColdFusion 10 Missing Feature - Form Fields and Arrays
I suggest that you remove the "[]" from the name since it disallows dot notation as mentioned in another answer.. When more than one form element contains the same name attribute, the browser will concatenate all of the values into a comma delimited string when submitting the form. Fortunately, ColdFusion has many functions which treat a delimited string as a list. You can use <cfloop> along with these functions to consume the list.
On JSON.org the essential data structures that JSON represents are given as
A collection of name/value pairs, and
An ordered list of values.
I have not been able to find anywhere whether a second member having the same name as one already parsed into the current object should (a) throw an exception or (b) replace the existing member.
Is this specified anywhere?
What do existing parsers do with repeated names?
EDIT: I am looking to define correct behavior for my parser.
JSON is simply a subset of the object literal notation of JavaScript and as such, is constrained by the same rules - the latest value for repeated keys will override any previously assigned value for that key, within the specific object. Think in terms of assigning a value to an object property; A later assignment will override an earlier one.
To demonstrate this, I have set up an example here. The code is displayed on the page, and as can be seen, the messagebox has the name 'Barney' in it.
Code here -
$(function() {
$('#myButton').click(function(e)
{
var myJsonString = "Person = {'firstName':'Fred','lastName':'Flintstone','firstName':'Barney'}";
eval("(" + myJsonString + ")");
alert(Person.firstName);
});
});
By the Way, I have used eval() here for ease of use. I would recommend using a JSON parser instead of eval() due to security issues.
They last name found by the parser is replaced by the new one. It doesn't throw an expection.
It is simply a Javascript syntax thing.
var json = {};
// lets augment the object
json.one = 1;
json.one = 2; // it gets replaced
I am pretty sure that both behaviors you list would be accepted, along with others (use the first one, use any of them). :-)
That is, such behavior is undefined from JSON specification POV.
As a practical matter, implementations I have used do either one of suggestions you mentioned, or "use the first one".
So no, I would not count on specific behavior given that tools can choose what to do.
Because JSON is simply a subset of Javascript, it largely depends upon the Javascript specification. I don't know personally what the answer is, but I would highly suggest not relying upon the behavior if at all possible.