2015-04-28 11 views
8

Załóżmy, że mam Foo.class w Javie:Czy istnieje sposób, aby "oczekiwać" wystąpienia określonej klasy Java w kodzie JavaScript?

public class Foo { 
    public int id; 
    public String data; 
} 

A że mam Foo "klasa" w JavaScript:

function Foo(id, data) { 
    this.id = id; 
    this.data = data; 
} 

Również załóżmy, że mam kontrolera Java, która zwraca instancję Foo .class jako odpowiedź na żądanie REST. W moim kodzie JavaScript (AngularJS) żądanie jest wysyłane jako:

$http.get(url + 'bar/get-foo/') 
    .success(function (response) { 
     var foo = new Foo(response.id, response.data); 
     logger.info("SUCCESS: /get-foo"); 
    }) 
    .error(function (error_message) { 
     logger.error(error_message) 
    }); 

I działa. Ale czy istnieje sposób na uniknięcie przekazywania każdej właściwości z odpowiedzi na konstruktor Foo (jakiegoś rodzaju oczekiwanie na obiekt Foo lub rzucenie go na obiekt Foo)?

Próbowałem za pomocą Object.create(Foo, response) ale mam TypeError: Property description must be an object: true

Oczywiście zawsze istnieje możliwość refactoring boczną Foo konstruktora JavaScript do:

function Foo(foo) { 
    this.id = foo.id; 
    this.data = foo.data; 
} 

Ale to wymagałoby Refactor dużych części kodzie .

Dzięki za poświęcony czas. Doceniam to!

PS: Dla tych, którzy zastanawiają się, dlaczego tego potrzebuję: nie ma problemu z małymi klasami, takimi jak Foo, ale niektóre odpowiedzi są przypadkami znacznie większych klas (z kilkunastoma polami), które nie są pod moim kontrola.

EDYCJA: Zaakceptowałem odpowiedź Chichozella tylko dlatego, że wymaga najmniejszej ilości pracy. Odpowiedzi Robina i jonnyknowsbest również działają (i będą działać dla czystego JavaScriptu, w przeciwieństwie do odpowiedzi Chichozella, która jest specyficzna dla AngularJS). Nie próbowałem odpowiedzi Laurentiu L., ale wygląda na to, że powinno również zadziałać. W każdym razie jest to rozwiązanie (nie rozwiązanie):

.success(function (response) { 
    var foo = new Foo(); 
    angular.extend(foo, response); // angular.merge() for "deep-copy" 
    //... 
} 

Wielkie dzięki dla wszystkich, którzy odpowiedzieli/komentowane/edytowane w tym wątku.

Odpowiedz

1

Jeśli chcesz zachować Java myślenia na javascript, spróbuj użyć angular.extend(), która „Kopiuj” właściwości obiektu do innego

this = angular.extend(this, response) 

w funkcji foo lub bezpośrednio na kontroler:

Foo = angular.extend(Foo, response) 
+0

Dzięki, nigdy nie wiedziałem o tych funkcjonalnościach AngularJS. – zkristic

1

można zrobić coś takiego z „deserialise” JSON otrzymasz z powrotem jako odpowiedź do inicjalizacji obiektu:

function JSONToObj(jsondata) { 
    var json = JSON.parse(jsondata); 

    var name = null; 
    for(var i in json) { //Use first property as name 
     name = i; 
     break; 
    } 

    if (name == null) 
     return null; 

    var obj = new window[name](); 
    for(var i in json[name]) 
     obj[i] = json[name][i]; 

    return obj; 
} 

ta zakłada, że ​​konstruktor istnieje w zasięgu globalnym i że odpowiedź jest JSON -formatowany jako taki:

{ 
    "Foo": { 
     "id": "the id", 
     "data": "the data" 
    } 
} 
+0

Wykonujesz pierwszą nieruchomość jako globalny konstruktor ...? –

+0

Och, myślę, że rozumiem! Być może w celu wyjaśnienia odpowiedzi podaj przykład, jak powinna wyglądać odpowiedź sformatowana w JSON. –

+0

Bardzo doceniam edycję Patrick: o) –

1

Można również zrobić coś w stylu this jsFiddle, aby uzyskać opisaną strukturę. Funkcja sprzęgająca createObject wygląda podobnie do następującego fragmentu kodu.

function createObject(response, toCreate){ 
    var newObject = new toCreate(); 
    for(var attr in response){ 
     if(newObject.hasOwnProperty(attr)){ 
      newObject[attr] = response[attr]; 
     } 
    } 
    return newObject; 
} 

Gdzie masz CreateObject która pobiera obiekt js z tymi samymi atrybutami jak swojej funkcji jako parametr odpowiedzi i funkcji (obiektu, który chcesz utworzyć) jako parametr tocreate.

Zobacz wyniki logu konsoli jsFiddle i widać, że to działa.

Można również, jak widać w jsFiddle, usunąć sprawdzanie hasOwnProperty, aby ustawić wszystkie atrybuty z odpowiedzi, niezależnie od tego, czy funkcja javascript je zdefiniowała.

1

Możesz zrobić to całkiem ogólne, jeśli chcesz. I nie byłoby zbyt wiele refaktoryzacji do zrobienia, a to rozwiązanie ułatwiłoby twoje przyszłe zmiany obu klasom.

Możesz zmienić obiekt javascript Foo na usługę Angular JS i wstrzyknąć ją tam, gdzie jej potrzebujesz. W ten sposób Twoje dane będą dostępne globalnie. Jest lepsza niż lokalna zmienna foo.

yourApp.factory('Foo', 
     function() { 
      //set a default or just initialize it 
      var fooObject= {}; 
      return { 
       getId: function() { return fooObject.id; }, 
       getData: function() { return fooObject.data;}, 
       setId: function(newId){fooObject.id = newId}, 
       setData: function(newData){fooObject.data=newData;}, 

       initializeFromObject : function(response){ 
        for (var prop in response){ 
          fooObject[prop] = response[prop]; 
        } 
       } 
      }; 
     } 
    ); 

Można także tworzenie nowych usług bezpieczniejsze metodami jak hasAllProperties (o iteracja właściwości obiektu, czy jest to tablica lub obiekt). ; hasNullValues ​​i tak dalej.

Mam nadzieję, że to pomaga i widzisz, że to wartość.

Powiązane problemy