Access Java Enum fields in javascript - javascript

I'm trying to access the facility String of this enum in java script
public enum FacilityEnum {
CAR_VALET("carValet"),
INDOOR("indoorPark"),
DISABLED_ACCESS("disabledAccess"),
EV_CHARGE("evCharge"),
private String facility;
private FacilityEnum(String facility) {
this.facility = facility;
}
public String getFacility() {
return facility;
}
public void setFacility(String facility) {
this.facility = facility;
}
}
This enum is used in a Facility.class
#Entity
public class Facility {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long facilityId;
#Enumerated(EnumType.STRING)
private FacilityEnum service;
#ManyToMany(mappedBy = "facilities")
#JsonBackReference("parks-facilities-services")
private Set<Park> parks;
}
public FacilityEnum getService() {
return service;
}
public void setService(FacilityEnum service) {
this.service = service;
}
which has a ManyToMany relation with Park.class.
The problem comes when i need to use the facility String in javascript
This the javascript interested part, i'm using Spring + Thymleaf
var parcheggi = JSON.parse([[${parks}]]); //my list of Parks
parcheggi.forEach(function (arrayItem) { //it's ok
var parcheggio = arrayItem;
var services = parcheggio.facilities; //it's ok, i get Facility objects
var servicesDiv = '<div>';
services.forEach(function (service){
var s = service; //the single Facility
servicesDiv += '<img src="/images/park_icons/facilities/' + s.service + '.png" />'
});
servicesDiv += '</div>';
//rest of the code...
In this case s.service is the rough Enum (CAR_VALET, INDOOR...) if i try s.service.facility I get undefined.. I need to have carValet, indoor, disabledAccess and so on...

One way to do what you want is to configure object mapper to serialize enums using toString method. You would add the following to the object mapper configuration:
objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
(Note that previous Jackson versions have equivalent to this property but it's different).
Then just add toString to your enum:
#Override
public String toString ()
{
return facility;
}

You are getting undefined because your Enum can't be deserialized in JSON, you have two options here:
Either change the Implementation of your Enum, so it contains only the Stringconstants and it will be correctly mapped by Jackson.
Your code would be:
public enum FacilityEnum {
CAR_VALET,
INDOOR,
DISABLED_ACCESS,
EV_CHARGE;
}
Or you should override the toString() method in your Enum so it can
be deserialized and returned as a String.
Your code would be:
public enum FacilityEnum {
CAR_VALET("carValet"),
INDOOR("indoorPark"),
DISABLED_ACCESS("disabledAccess"),
EV_CHARGE("evCharge"),
private String facility;
private FacilityEnum(String facility) {
this.facility = facility;
}
public String getFacility() {
return facility;
}
public void setFacility(String facility) {
this.facility = facility;
}
#Override
public String toString() {
return facility;
}
}

Related

Is it possible to have a method in C# that implicitly deserializes an argument if it's passed as a JSON string?

Question
I have a handful of ViewComponents that look like so:
public IViewComponentResult Invoke(BuyerViewModel buyer)
I'd like them to be able to accept either a BuyerViewModel, or a JSON string representing a BuyerViewModel. For example, when you pass JSON to a controller method from JavaScript, if that method expects an argument of type Dog, the controller automatically attempts to deserialize the JSON to an instance of Dog. I'm trying to mimic that behavior.
The goal would be that both of these examples work:
var buyer = new BuyerSummaryViewModel() { FirstName = "John" };
ViewComponent("Buyer", buyer);
ViewComponent("Buyer", "{\"Name\":\"John Smith\"}");
Why?
I'm trying to make a generic JavaScript method that can fetch a ViewComponent on the fly:
const fetchViewComponent = async (viewComponentName, viewModel) => {
let data = { viewComponentName, viewModel };
let html = await $.get(`/Order/FetchViewComponent`, data);
return html;
}
//Get a BuyerViewComponent (example)
(async () => {
let component = await fetchViewComponent("Buyer", `#Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.Buyer))`);
console.log(component);
})();
What I've Tried
If I specify that the ViewModel is a BuyerViewModel, it works. The JSON string is automatically deserialized into a BuyerViewModel.
public class FetchViewComponentRequest
{
public string ViewComponentName { get; set; }
public BuyerViewModel ViewModel { get; set; }
// ^^^^^^^^^^^^^^
}
[HttpGet]
public IActionResult FetchViewComponent(FetchViewComponentRequest request)
{
return ViewComponent(request.ViewComponentName, request.ViewModel);
}
The Issue
However, I don't want to specify the type; I want this to be generic. So I tried this:
public class FetchViewComponentRequest
{
public string ViewComponentName { get; set; }
public string ViewModel { get; set; }
// ^^^^^^
}
[HttpGet]
public IActionResult FetchViewComponent(FetchViewComponentRequest request)
{
return ViewComponent(request.ViewComponentName, request.ViewModel);
}
But as expected, request.ViewModel isn't the correct type; it ends up null in the Invoke method. I was hoping there was a flag or something more global I could specify so that it tries to implicitly deserialize this string into the expected type.
Is there an easier way to do this that I haven't considered? Or, if not, is the way I'm envisioning even possible?
(I'm using .NET Core 2.2)
Maybe make your FetchViewComponentRequest generic?
public class FetchViewComponentRequest<T>
{
public string ViewComponentName { get; set; }
public T ViewModel { get; set; }
// ^^^^^^^^^^^^^^
}
[HttpGet]
public IActionResult FetchViewComponent(FetchViewComponentRequest<BuyerViewModel> request)
{
return ViewComponent(request.ViewComponentName, request.ViewModel);
}
The method needs to have some knowledge of what type to make the object coming in.
public T Convert<T>(dynamic obj) where T:class,new()
{
T myob = null;
if (obj !=null && obj is T)
{
myob = obj as T;
}
else if (obj is string)
{
//convert to type
myob = JsonConvert.DeserializeObject<T>(obj);
}
return myob;
}
Ok, im not sure about what you need.
But here is a dynamic way to do it, without specifying <T>.
//Assume that the namespace is DynamicTypeDemo
public class DynamicType {
// eg "DynamicTypeDemo.Cat, DynamicTypeDemo"
public string TypeName { get; set; } // the full path to the type
public string JsonString { get; set; }
}
Now you could simple DeserializeObject
public object ToObject(DynamicType dynamicType){
var type = Type.GetType(dynamicType.TypeName);
// Here you could check if the json is list, its really upp to you
// but as an example, i will still add it
if (dynamicType.JsonString.StartsWith("[")) // its a list
type =(List<>).MakeGenericType(type);
return JsonConvert.DeserializeObject(dynamicType.JsonString, type);
}
And here is how it work
var item = new DynamicType(){
TypeName = "DynamicTypeDemo.Cat, DynamicTypeDemo", // or typeof(Cat).AssemblyQualifiedName
JsonString = "{CatName:'Test'}"; // And for a list "[{CatName:'Test'}]"
}
object dynamicObject= ToObject(item); // return it to the javascript
Cat cat = dynamicObject as Cat; // Cast it if you want

How to pass dictionary with empty array as value

I have this class:
public class State{
public Dictionary<SecurityType, List<long>> assets { get; set; }
}
And action:
[HttpPost]
public virtual ActionResult GetHoldings(State state)
{
return Json(new HoldingsBL().GetHoldings(state));
}
public enum SecuritySerachType
{
Company = 1,
Security,
}
when i try to pass something like this:
{state:{assets :[{"Key":1,"Value":[]}]}}
i got empty dictionary in asset property.
i already read this solution , but i don`t realize how to solve my problem.
Some easy solution?
edit:
I try to add ValueProviderFactory as Oleksii Aza said, but there is a problem to compare it to backingStore(there is already exist a dictionary check, probably for nested objects):
var d = value as IDictionary<string, object>;
if (d != null)
{
foreach (var entry in d)
{
AddToBackingStore(backingStore, MakePropertyKey(prefix, entry.Key), entry.Value);
}
return;
}
So i still stuck with this issue.
Try using object-like JSON structure for C# Dictionary, for example:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
public class Program
{
public enum SecuritySerachType
{
Company = 1,
Security,
}
public class State{
public Dictionary<SecuritySerachType, List<long>> assets { get; set; }
}
public static void Main()
{
var state = JsonConvert.DeserializeObject<State>(#"{assets :{""1"":[]}}");
Console.WriteLine(state.assets[SecuritySerachType.Company].Count);
}
}
Link to dotnet fiddle

Bad request errror between spring boot and angularjs by a post request

I have two small projects, backend spring-boot side is responsible for providing the data, and angularjs frontend part is just displaying that data. I am trying to post a json from angular side and spring-boot side consumes and sends a respond.
This is horse racing data in json; "jokey" means rider and contains rider information:
var list = {"horses": [{"horseId":45942,"horseName":"Decolte","raceId":8449,"kilo":61.0,"jokey":{"name":"AYETULLAH DEMİR","raceNumber":41,"first":1,"second":4,"third":0,"fourth":1},"ekuriId":0},
{"horseId":27520,"horseName":"Busıness Man","raceId":8449,"kilo":57.0,"jokey":{"name":"CİVAN ÖZŞAHİN","raceNumber":190,"first":7,"second":15,"third":18,"fourth":12},"ekuriId":0},
{"horseId":55856,"horseName":"Erselçuk","raceId":8449,"kilo":57.0,"jokey":{"name":"NAİL EREN","raceNumber":64,"first":2,"second":0,"third":4,"fourth":2},"ekuriId":0},
{"horseId":52940,"horseName":"Haşim Ağa","raceId":8449,"kilo":57.0,"jokey":{"name":"DOĞUKAN AYDOĞAN","raceNumber":380,"first":11,"second":18,"third":10,"fourth":24},"ekuriId":0},
{"horseId":53431,"horseName":"İhtiyar","raceId":8449,"kilo":57.0,"jokey":{"name":"CÜNEYİT GÖKÇE","raceNumber":598,"first":32,"second":52,"third":64,"fourth":65},"ekuriId":0},
{"horseId":51778,"horseName":"Urla Zamanı","raceId":8449,"kilo":57.0,"jokey":{"name":"ADEM ŞEN","raceNumber":280,"first":18,"second":25,"third":32,"fourth":32},"ekuriId":0},
{"horseId":51816,"horseName":"Wın Every Day","raceId":8449,"kilo":57.0,"jokey":{"name":"EMRE NALBANT","raceNumber":405,"first":19,"second":26,"third":36,"fourth":33},"ekuriId":0},
{"horseId":58650,"horseName":"Lıon Amed","raceId":8449,"kilo":52.0,"jokey":{"name":"CANER KARADEMİR","raceNumber":134,"first":7,"second":7,"third":8,"fourth":7},"ekuriId":0},
{"horseId":51239,"horseName":"Catch The Wınd","raceId":8449,"kilo":57.0,"jokey":{"name":"MÜSLÜM CANPOLAT","raceNumber":238,"first":5,"second":12,"third":12,"fourth":19},"ekuriId":0},
{"horseId":46263,"horseName":"Ian Tapp","raceId":8449,"kilo":58.0,"jokey":{"name":"ERDEM NUR TÜFEKÇİ","raceNumber":79,"first":3,"second":1,"third":4,"fourth":5},"ekuriId":0},
{"horseId":51647,"horseName":"Sılverado","raceId":8449,"kilo":57.0,"jokey":{"name":"ÜMİT DERYA ALTEKİN","raceNumber":1185,"first":48,"second":53,"third":64,"fourth":84},"ekuriId":0},
{"horseId":57231,"horseName":"Junıor Duru","raceId":8449,"kilo":58.0,"jokey":{"name":"BEDRİ TEPE","raceNumber":716,"first":45,"second":55,"third":50,"fourth":67},"ekuriId":0}
]};
It was basically an array but somebody on stackoverflow told the data inside ajax request should be an object so I added "horses:" to the front. The json is manually added inside the code.
This is http request:
$http({
url: 'http://localhost:8080/horseHistory',
method: 'POST',
contentType: "application/json",
data: list.horses,
headers: {
"Content-Type": "application/json"
}
}).success(function(data) {
console.log(data);
});
On the backend I just want to see a working http connection so it is mostly empty. This is spring-boot function:
#RequestMapping(value = "/horseHistory", method = RequestMethod.POST )
public ResponseEntity<Void> getHorseHistory(#RequestBody HorseRaceModel[] horseRaces) throws IOException {
System.out.println(horseRaces[0]);
return null;
}
HorseRaceModel:
package ganyan;
public class HorseRaceModel {
int horseId;
String horseName;
int raceId;
double kilo;
JokeyModel jokey;
int ekuriId;
public HorseRaceModel(int horseId, String horseName, int raceId, double kilo, JokeyModel jokey, int ekuriId) {
this.horseId = horseId;
this.horseName = horseName;
this.raceId = raceId;
this.kilo = kilo;
this.jokey = jokey;
this.ekuriId = ekuriId;
}
public int getHorseId() {
return horseId;
}
public void setHorseId(int horseId) {
this.horseId = horseId;
}
public void setHorseName(String horseName) {
this.horseName = horseName;
}
public String getHorseName() {
return horseName;
}
public int getRaceId() {
return raceId;
}
public void setRaceId(int raceId) {
this.raceId = raceId;
}
public double getKilo() {
return kilo;
}
public void setKilo(double kilo) {
this.kilo = kilo;
}
public JokeyModel getJokey() {
return jokey;
}
public void setJokey(JokeyModel jokey) {
this.jokey = jokey;
}
public int getEkuriId() {
return ekuriId;
}
public void setEkuriId(int ekuriId) {
this.ekuriId = ekuriId;
}
}
JokeyModel:
public class JokeyModel {
private String name;
private int raceNumber;
private int first;
private int second;
private int third;
private int fourth;
public int getSecond() {
return second;
}
public void setSecond(int second) {
this.second = second;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getRaceNumber() {
return raceNumber;
}
public void setRaceNumber(int raceNumber) {
this.raceNumber = raceNumber;
}
public int getFirst() {
return first;
}
public void setFirst(int first) {
this.first = first;
}
public int getThird() {
return third;
}
public void setThird(int third) {
this.third = third;
}
public int getFourth() {
return fourth;
}
public void setFourth(int fourth) {
this.fourth = fourth;
}
}
The error from Chrome console:
Failed to load resource: the server responded with a status of 400 (Bad Request) http://localhost:8080/horseHistory
The error from Java console:
nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.HashMap out of START_ARRAY token
I'm not familiar with Spring Boot and I don't know why you have been told to post a JSON object instead of a JSON array, but I see that you are not doing it coherently.
You wrapped your JSON array in a JSON object called list, but by specifying data: list.horses you are still only passing the embedded JSON array. Since you want to send the whole JSON object, you should specify data: list instead.
Furthermore, I think that you need to define the wrapper model on the server side, which may be some class like this:
public class ListModel {
private List<HorseRaceModel> horses;
public List<HorseRaceModel> getHorses() {
return horses;
}
public void setHorses(List<HorseRaceModel> horses) {
this.horses = horses;
}
}
Finally, the method consuming the post should be instructed to parse the request body into a ListModel. This means to modify the method to something like this:
#RequestMapping(value = "/horseHistory", method = RequestMethod.POST )
public ResponseEntity<Void> getHorseHistory(#RequestBody ListModel horseRaces) throws IOException {
System.out.println(horseRaces.getHorses().get(0).getName());
return null;
}
Side note: I also modified the code to print the name of the first horse instead of the object pointer that would be printed by System.out.println(horseRaces.getHorses().get(0));. You may want to print something else instead. You may also want to use better names for the wrapper object and model (instead of list and ListModel)
Note from comment: Your HorseRaceModel class does not have an empty constructor, you need to provide one for deserialization to work

JQuery modified Hidden Field Value is empty when posted back to the server

Summary: I have a web control that is dynamically added to the page. The control has a HiddenField child control. I am passing the control's ClientID to a jquery widget that is setting the value to a string (json converted to string). When the form is posted back to the server, the value of the HiddenField is a blank string. I value is in the Request.Form[UniqueID] object. The value is making it back to the server. The problem is that, I don't have access to the Request object when I need the value without modifying a lot of legacy code.
The strange thing is that the selectmany control is the one I am having a problem with, but it inherits from the SelectOne that is working properly. I think I am doing something wrong in the selectmany class because even if I try to push a value into the SelectOneHiddenValue it does not work ,but it works properly when the SelectOne uses it.
SelectOne:
[ToolboxData("<{0}:SelectOne runat=server></{0}:SelectOne>")]
public class SelectOne : Panel, IControl,ISelectOne
{
#region structure
private readonly Panel _selectOneTextboxContainer = new Panel();
protected readonly TextBox SelectOneTextbox = new TextBox();
protected readonly HiddenField SelectOneHiddenValue = new HiddenField();
private readonly Panel _selectOneDropdownImageContainer = new Panel();
private readonly Image _selectOneDropDownImage = new Image();
#endregion
private readonly IList<LookupItem> _selectedItems = new List<LookupItem>();
#region properties
public IList<LookupItem> SelectedItems { get { return _selectedItems; } }
public bool MultiSelect { get; set; }
public DisplayOption Display { get; set; }
public string Name { get; set; }
[DefaultValue(0)]
public int LookupValueOrgID
{
get
{
EnsureChildControls();
return Convert.ToInt32(String.IsNullOrEmpty(SelectOneHiddenValue.Value) ? "0" : SelectOneHiddenValue.Value);
}
set
{
EnsureChildControls();
SelectOneHiddenValue.Value = value.ToString();
}
}
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string Text
{
get
{
EnsureChildControls();
return SelectOneTextbox.Text;
}
set
{
EnsureChildControls();
SelectOneTextbox.Text = value;
}
}
/// <summary>
/// The minimum number of characters a user has to type before the autocompleter activates.
/// </summary>
[Bindable(true)]
[Category("Appearance")]
[DefaultValue(1)]
[Localizable(true)]
public int MinChars
{
get
{
int b = (ViewState["MinChars"] == null ? 1 : (int)ViewState["MinChars"]);
return b;
}
set
{
ViewState["MinChars"] = value;
}
}
/// <summary>
/// The number of backend query results to store in cache. If set to 1 (the current result), no caching will happen. Must be >= 1.
/// </summary>
[Bindable(true)]
[Category("Appearance")]
[DefaultValue(10)]
[Localizable(true)]
public int CacheLength
{
get
{
int b = (ViewState["CacheLength"] == null ? 10 : (int)ViewState["CacheLength"]);
return b;
}
set
{
ViewState["CacheLength"] = value;
}
}
public string OuterMarkupClientID
{
get { return "SelectOne_Container" + ClientID; }
}
/// <summary>
/// If true, target input text is appended to
/// If false, target input text is replaced
/// </summary>
public bool AppendSelectedTextToInput { get; set; }
public virtual string ContainerClass
{
get { return "SelectOneContainer"; }
}
#endregion
#region constructor
public SelectOne()
{
SetCssClasses();
}
#endregion
#region lifecycle overrides
protected override void CreateChildControls()
{
base.CreateChildControls();
AddChildrenToControlCollection();
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
SetupClientEvents();
ControlHelper.AddRequiredControl(this);
var resourceName = string.Empty;
var cs = Page.ClientScript;
resourceName = "UI.Controls.resources.images.DropDownButton.gif";
_selectOneDropDownImage.ImageUrl = cs.GetWebResourceUrl(GetType(), resourceName);
SelectOneTextbox.Attributes.Add("lookupOrgID", LookupOrgID.ToString());
SelectOneTextbox.Attributes.Add("cacheLength", CacheLength.ToString());
SelectOneTextbox.Attributes.Add("service", Service);
SelectOneTextbox.Attributes.Add("selectOneTextboxId", SelectOneTextbox.ClientID);
SelectOneTextbox.Attributes.Add("selectOneHiddenValueId",SelectOneHiddenValue.ClientID);
}
#endregion
#region private helpers
private void SetCssClasses()
{
this.CssClass = ContainerClass + " AutocompleteContainer";
_selectOneDropDownImage.CssClass = "SelectOneDropDownImage";
SelectOneTextbox.CssClass = "SelectOneTextbox QuantifiTextBox";
_selectOneTextboxContainer.CssClass = "SelectOneTextboxContainer";
_selectOneDropdownImageContainer.CssClass = "SelectOneDropDownImageContainer";
}
private void SetupClientEvents()
{
ControlHelper.RegisterAutoCompleteScript(this);
var resourceName = "UI.Controls.resources.scripts.SelectOne.js";
string js;
using (var sr = new StreamReader(GetType().Assembly.GetManifestResourceStream(resourceName)))
{
js = sr.ReadToEnd();
sr.Close();
}
ClientScriptProxy.Current.RegisterStartupScript(this, typeof(SelectOne), "SelectOneJS", js, true);
_selectOneDropDownImage.Attributes.Add("onclick", "SelectOne_ImageClick('" + SelectOneTextbox.ClientID + "');");
}
private void AddChildrenToControlCollection()
{
_selectOneTextboxContainer.Controls.Add(SelectOneTextbox);
this.Controls.Add(_selectOneTextboxContainer);
_selectOneDropdownImageContainer.Controls.Add(_selectOneDropDownImage);
this.Controls.Add(_selectOneDropdownImageContainer);
this.Controls.Add(SelectOneHiddenValue);
}
#endregion
}
Select Many:
[ToolboxData("<{0}:SelectMany runat=server></{0}:SelectMany>")]
public class SelectMany : SelectOne, ISelectMany
{
#region structure
private readonly Panel _selectedItemsPanel = new Panel();
private readonly HiddenField _selectManyHiddenField = new HiddenField();
public override string ContainerClass
{
get
{
return "SelectManyControlContainer";
}
}
#endregion
public SelectMany()
{
MultiSelect = true;
}
#region lifecycle overrides
protected override void CreateChildControls()
{
base.CreateChildControls();
_selectManyHiddenField.ID = "SelectedItemsHiddenValue";
this.Controls.Add(_selectedItemsPanel);
this.Controls.Add(_selectManyHiddenField);
SelectOneTextbox.Attributes.Add("data-multiselect", MultiSelect.ToString());
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
var resourceName = "jquery.SelectedItemCollection.js";
ClientScriptProxy.Current.RegisterClientScriptInclude(this, Page.ClientScript.GetWebResourceUrl(this.GetType(),resourceName));
var serializer = new JavaScriptSerializer();
var startupScript = String.Format("\n$('#{0}').each(function(){{" +
"var selectedPlugin = $(this).SelectedItemCollection(" +
" {{" +
" itemData: {1}," +
" deleteImageUrl: '{2}'," +
" selectedTextId: '{3}', " +
" hiddenTextFieldId: '{4}' " +
" }});}});\n",
this.ClientID,
serializer.Serialize(SelectedItems),
GetDeleteImageUrl(),
SelectOneTextbox.ClientID,
_selectManyHiddenField.ClientID
);
ClientScriptProxy.Current.RegisterStartupScript(this,this.GetType(),"SelectedItemsJs_" + this.ClientID,startupScript,true);
}
#endregion
#region public api
public void BindForm()
{
EnsureChildControls();
this.DataBind();
var jsonString = _selectManyHiddenField.Value;
SelectedItems.Clear();
if (!jsonString.IsNullOrEmpty())
{
Json.Decode<IEnumerable<LookupItem>>(jsonString).ForEach(li => SelectedItems.Add(li));
}
}
#endregion
private string GetDeleteImageUrl()
{
var cs = Page.ClientScript;
const string resourceName = "UI.Controls.resources.images.close.gif";
return cs.GetWebResourceUrl(this.GetType(), resourceName);
}
}
Well, it was something stupid. And it took me forever to find. Basically, don't misuse the EnsureChildControls() method. The base class was calling that before some of it's properties were accessed. This called RecreateChildControls() after ViewState was restored, but before I could check the values.
To correct this, I added EnsureChildControls() in the OnInit override for both the base class and the derived class. That way, all my controls will be created properly and ViewState is restored after their creation.
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
EnsureChildControls();
}

How do I assign a JSONObject or JavaScriptObject to $wnd[x] in GWT?

I read some var from my HTML-Page using GWT Dictionary. The var looks like this:
var test = {
"a" : "123",
"b" : "jg34l",
...
}
Now I get via AJAX-Call new content for my JS var. At the moment I overwrite it like this:
public native void set(String key, String value) /*-{
$wnd["test"][key] = value;
}-*/;
public void onResponseReceived(Request request, Response response) {
JSONObject obj = (JSONObject) JSONParser.parseLenient(response.getText());
for (String key : obj.keySet()) {
JSONString val = (JSONString) obj.get(key);
set(key, val.stringValue());
}
}
As you can see I get a JSON-String. Parse it. Cast it to JSONObject. Take every key-value-pair and use the JSNI-method to set the pairs.
There must be an easier way to do this?! I want simply to say: $wnd["test"] = myJsonObject
Please help me, 'cause it is performance-critical step (up to 1000 key-value-pairs).
You can try using JSO (should be also much faster than JSONObject)
Something like this:
public native void set(JavaScriptObject data) /*-{
$wnd['test'] = data;
}-*/;
public void onResponseReceived(Request request, Response response) {
JavascriptObject data = JsonUtils.safeEval(response.getText()).case();
set(data);
}
I haven't tried myself, so I can't say 100% if it would work.
Update:
Instead of a Dictionary you can directly return a JavaScriptObject that supports hash like access:
public class MyDictionary extends JavaScriptObject {
public native String get(String name) /*-{
return this[name];
}-*/;
}
public native MyDictionary getData() /*-{
return $wnd['test'];
}-*/
Here's my version for GWT Dictionary (true dynamic language switch):
public native void setTranslation(String locale, JavaScriptObject translationData) /*-{
$wnd[locale] = translationData;
}-*/
#Inject
TranslationProvider translationProvider;
public void onResponseReceived(Request request, Response response) {
String newLocale = "en";
JavaScriptObject translationData = JsonUtils.unsafeEval(response);
setTranslation(newLocale, translationData);
translationProvider.setLocale(newLocale);
LocaleChangeEvent.fire(eventBus);
}
Every Widget that displays translatable text registers to LocaleChangeEvent and implements LocaleChangeEventHandler:
public interface LocaleChangeEventHandler extends EventHandler {
void onLocaleChange(LocaleChangeEvent event);
}
In the onLocaleChange method it simply calls the get(...) method from the TranslationProvider class to receive its String:
public class LocaleAwareLabel extends Label implements LocaleChangeEventHandler {
TranslationProvider translationProvider;
#Inject
public LocaleAwareLabel(TranslationProvider translationProvider, EventBus eventBus) {
this.translationProvider = translationProvider;
eventBus.addHandler(LocaleChangeEvent.TYPE, this);
get();
}
public void get() {
this.setText(translationProvider.get("myDictionaryKey"));
}
#Override
public void onLocaleChange(LocaleChangeEvent event) {
get();
}
}
And here the TranslationProvider class:
#Singleton
public class TranslationProvider {
Dictionary dictionary;
public void setActiveLocale(String locale) {
dictionary = Dictionary.getDictionary(locale);
}
public String get(String key) {
dictionary.get(key);
}
}
That's it!

Categories

Resources