0

estoy efectuando el refactoring de un codigo, prototipando los elementos.

lo que note es que al llamar una de las funciones que tengo : scheda.prototype.getValori, la cual hace una llamada asincrona para cargar los datos de el area SharePoint, se me ejecuta el codigo antes de que la llamada este terminada. en efecto debugeando con el console.log me retorna un valor nulo al interno de una de las variables del objeto.

el codigo que tengo es el siguiente :

CLASS

function shceda(){
    this.ID;
    this.titolo;
    this.statoScheda;
    this.Corpo;
    this.CorpoOriginale;
    this.CorpoPubblico;
    this.GruppoPubblicazione;
    this.versioneScheda;
    this.pubblicazioneImmediata;
    this.baseLegale;
    this.annoAttivazione;
    this.annoScadenza;
    this.dataAttivazione;
    this.dataScadenza;
    this.commento1;
    this.commento2;
    this.commento3;
    this.statoSchedaEsterna;
    this.lookupId;
    this.tipologia;
    this.tConsultazione;
    this.tApprovazione;
    this.tAttivazione;
    this.allegati = [];
    this.link = [];
    this.referenze;
}
scheda.prototype.getValori = function(ID, nomeLista){
    $.ajax({
        url: "********('"+ nomeLista +"')/items(" + ID + ")",
        type: "GET",
        headers: {
            "ACCEPT": "application/json;odata=verbose"
        },
        success: function (data){
            console.log(data.d.Title);
            this.ID = data.d.Id;
            this.titolo = data.d.Title;
            this.statoScheda = data.d.StatoScheda;
            this.Corpo = data.d.Corpo;
            this.CorpoOriginale = data.d.CorpoOriginale;
            this.CorpoPubblico = data.d.CorpoPubblico;
            this.GruppoPubblicazione = data.d.Gruppo_x0020_di_x0020_pubblicazi;
            this.versioneScheda = data.d.versioneScheda;
            this.pubblicazioneImmediata = data.d.pubblicazione_x0020_immediata;
            this.baseLegale = data.d.BaseLegale;
            this.annoAttivazione = data.d.AnnoDiAttivazione;
            this.annoScadenza = data.d.AnnoDiScadenza;
            this.dataAttivazione = data.d.DataDiAttivazione;
            this.dataScadenza = data.d.DataDiScadenza;
            this.commento1 = data.d.commento1;
            this.commento2 = data.d.commento2;
            this.commento3 = data.d.commento3;
            this.statoSchedaEsterna = data.d.StatoSchedaEsterna;
            this.lookupId = data.d.lookupID; 
            this.tipologia = data.d.Tipo_x0020_Scheda;
            this.tConsultazione = data.d.t_consultazione;
            this.tApprovazione = data.d.t_approvazione;
            this.tAttivazione = data.d.t_attivazione;
            this.referenze = data.d.referenze;
        },
        error: function(err){
            console.log(JSON.stringify(err));
        }
    })
};

y lo estoy llamando de la siguiente manera :

 var proposta = new scheda();
 proposta.getValori(getParameterByName("ID"), $("#DeltaPlaceHolderPageTitleInTitleArea .die a").html()) //la segunda seria el nombre de la lista
 //aca va el codigo donde lleno los campos con las variables un ejemplo : 
 $("#titolo").html(proposta.titolo);

solo que console.log(proposta.titolo) me retorna undefined

he probado a hacer lo siguiente :

//no funciono porque $().done() no es una funcion
$(function(){ proposta.getValori(id,nombreLista)}.done(function(){...})
//no funciono porque $().then() no es una funcion
$(function(){ proposta.getValori(id,nombreLista)}.then(function(){...})
//no me funciono tampoco 
var proposta = new scheda();
proposta.getValori(...);
$(document).ready(function(){...});
//probe a meterlo en una variable y usar el done() pero tampoco: 
var prop = proposta.getValori(...);
prop.done(function(){...});
//y tambien 
prop.then(function(){...});

la verdad es que no se mas que probar, tendrian alguna idea de como puedo hacer ? sin tener que hacer un work arround con un setTimeout() ya que no es para nada elegante ni 100% efectivo (personalmente no me gusta para nada esa idea).

desde ya muchas gracias!

EDIT

momentaneamente solucione de la siguiente manera :

  scheda.prototype.getValori= function(id,nomeLista){
      .....
      stampa(); //imprimir

y simplemente agregue mi codigo en una función llamada stampa() en la pagina donde creo el objeto.

si existe alguna otra forma que sea mejor bienvenido sea !

Momentaneamente espero alguna respuesta que talvez sea mejor como solución.

Federico
  • 1,471
  • 7
  • 23
  • 1
    La cuestión es muy sencilla, debes tratar los datos relativos a la respuesta de Ajax dentro del `success` o si no quieres hacerlo ahí, pasarlos de ahí a otra función. En tu caso esto: `$("#titolo").html(proposta.titolo);` si lo pones dentro del `success` no vas a tener el problema actual, porque Ajax entra ahí cuando ha retornado del servidor y cuando la petición ha sido exitosa. – A. Cedano Feb 13 '19 at 10:28
  • @A.Cedano eso si, pero voveria a la situación actual es decir realizar la misma petición de diferentes modos y la prototipación perderia sentido. yo ahora por ejemplo tengo tres diferentes hojas js que hacen exactamente la misma petición solo que cambia la elaboración de los datos, es por eso que quise centralizar todo y crear esta clase. no se si me explique correctamente, gracias de todos modos – Federico Feb 13 '19 at 10:34
  • La verdad es que no me detuve a leer todo el código que compartes y a analizar su lógica, porque tampoco es que la pregunta esté planteada de una forma *apetecible* en el sentido de que sueltas el código sin explicar mucho el contexto. Leyendo tu comentario parecería que haces justo lo contrario de lo que deberías hacer. O sea, si la petición es la misma y lo único que cambia son los datos, puedes crear una función que lance la petición y cuando la necesites la llamas, pasándole los datos que se generen en cada contexto. – A. Cedano Feb 13 '19 at 10:38
  • @A.Cedano eso es lo que estoy haciendo, simplemente que la funcion es un prototipo de una clase – Federico Feb 13 '19 at 11:03
  • Pero ¿esto `console.log(data.d.Title);` muestra correctamente el dato o muestra `undefined`? ¿Qué muestra un `cosole.log(data);`? – A. Cedano Feb 13 '19 at 11:07
  • A menos que uses una llamada **sincrona** los datos estarán `undefined` si los usas inmediatamente. Usar un `setTimeout()` sería una media desesperada, que ralentizaría de más o seguiría devolviendo `undefined`. Creo que lo mejor sería pasar como parámetro una función, que se ejecutará en el `success` del ajax. – Fly Feb 13 '19 at 11:35
  • Sería como tu solución actual (la función stampa() ) pero más organizado: `scheda.prototype.getValori= function(id,nomeLista, callback)...` – Fly Feb 13 '19 at 11:37
  • @Fly si la verdad que no lo habia pensado, creo que es la mejor solución, agregala como respuesta asì te la marco como correcta – Federico Feb 13 '19 at 12:49
  • de la forma antigua `callbacks`, de la forma actual `Promises`, forma actual mejorada `Observables` (RxJS) – LPZadkiel Feb 13 '19 at 14:06
  • 2
    Posible duplicado de [Reutilizar ajax](https://es.stackoverflow.com/questions/169297/reutilizar-ajax) – JackNavaRow Feb 13 '19 at 15:04

3 Answers3

2

Como he dicho en los comentarios, una opción a tener en cuenta es añadir un parámetro que sea una función para tratar los datos una vez el ajax ha finalizado.

Esta función de retorno se podría ejecutar según guste en los eventos: success, error y/o complete. Remito a la documentación oficial para analizar ese tema.

En este caso he añadido una función en el success y otra en el error.

Por lo tanto quedaría:

function shceda(){
    this.ID;
    this.titolo;
    this.statoScheda;
    this.Corpo;
    this.CorpoOriginale;
    this.CorpoPubblico;
    this.GruppoPubblicazione;
    this.versioneScheda;
    this.pubblicazioneImmediata;
    this.baseLegale;
    this.annoAttivazione;
    this.annoScadenza;
    this.dataAttivazione;
    this.dataScadenza;
    this.commento1;
    this.commento2;
    this.commento3;
    this.statoSchedaEsterna;
    this.lookupId;
    this.tipologia;
    this.tConsultazione;
    this.tApprovazione;
    this.tAttivazione;
    this.allegati = [];
    this.link = [];
    this.referenze;
}
scheda.prototype.getValori = function(ID, nomeLista, callBackSuccess, callBackFail){
    $.ajax({
        url: "********('"+ nomeLista +"')/items(" + ID + ")",
        type: "GET",
        headers: {
            "ACCEPT": "application/json;odata=verbose"
        },
        success: function (data){

            // console.log(data.d.Title);
            this.ID = data.d.Id;
            this.titolo = data.d.Title;
            this.statoScheda = data.d.StatoScheda;
            this.Corpo = data.d.Corpo;
            this.CorpoOriginale = data.d.CorpoOriginale;
            this.CorpoPubblico = data.d.CorpoPubblico;
            this.GruppoPubblicazione = data.d.Gruppo_x0020_di_x0020_pubblicazi;
            this.versioneScheda = data.d.versioneScheda;
            this.pubblicazioneImmediata = data.d.pubblicazione_x0020_immediata;
            this.baseLegale = data.d.BaseLegale;
            this.annoAttivazione = data.d.AnnoDiAttivazione;
            this.annoScadenza = data.d.AnnoDiScadenza;
            this.dataAttivazione = data.d.DataDiAttivazione;
            this.dataScadenza = data.d.DataDiScadenza;
            this.commento1 = data.d.commento1;
            this.commento2 = data.d.commento2;
            this.commento3 = data.d.commento3;
            this.statoSchedaEsterna = data.d.StatoSchedaEsterna;
            this.lookupId = data.d.lookupID; 
            this.tipologia = data.d.Tipo_x0020_Scheda;
            this.tConsultazione = data.d.t_consultazione;
            this.tApprovazione = data.d.t_approvazione;
            this.tAttivazione = data.d.t_attivazione;
            this.referenze = data.d.referenze;

            callBackSuccess(data)
        },
        error: function(err){
            callBackFail(err)
            // console.log(JSON.stringify(err));
        }
    })
};

Ahora, al delegar el procesado de datos a una función externa, habría que establecer si se necesita, o no, que el propio objeto los almacene. Además de si procede añadir un método o propiedad para evaluar el estado de la llamada asíncrona.

La llamada quedaría:

 var proposta = new scheda();
 proposta.getValori(getParameterByName("ID")
    , $("#DeltaPlaceHolderPageTitleInTitleArea .die a").html()  //la segunda seria el nombre de la lista
    , function(data){ // callbackSuccess
        $("#titolo").html(data.titolo);
        // resto de campos ...
    }
    , function(data){  // callbackError
        // mostramos un texto de error
        $("#titolo").html('Si è verificato un errore.');
        // o podemos analizar en profundidad
        // error = JSON.stringify(data);

    }) 

NOTA:

La llamada al método getValori() no devolverá nada, no estaría de más devolver un booleano, para el caso en que no se pueda ejecutar el ajax y por tanto no se ejecute ningún callback.

Fly
  • 1,664
  • 2
  • 7
  • 15
1

Lo que yo haría sería añadir un tercer parametro "callback" a tu función, que se ejecute tras el success:

scheda.prototype.getValori = function(ID, nomeLista,callback){
$.ajax({
        url: "********('"+ nomeLista +"')/items(" + ID + ")",
        type: "GET",
        headers: {
            "ACCEPT": "application/json;odata=verbose"
        },
        success: function (data){
           ...
           callback(this)
        }
});
}

De esta forma puedes llamar a la función pasándole qué quieres hacer después con los datos:

 var proposta = new scheda();
 proposta.getValori(getParameterByName("ID"),
    $("#DeltaPlaceHolderPageTitleInTitleArea .die a").html(),
    function(datos){
       $("#titolo").html(proposta.titolo);
    })

Un saludo.

1

Ya tienes otras respuestas que te comentan la solución del callback, pero existe una solución que personalmente veo más elegante: devolver la promesa que crea jQuery. El código quedaría así:

scheda.prototype.getValori = function(ID, nomeLista){
    return $.ajax({ //devolvemos la promesa
        url: "********('"+ nomeLista +"')/items(" + ID + ")",
        type: "GET",
        headers: {
            "ACCEPT": "application/json;odata=verbose"
        },
    }).then(function (data){
            console.log(data.d.Title);
            this.ID = data.d.Id;
            this.titolo = data.d.Title;
            this.statoScheda = data.d.StatoScheda;
            this.Corpo = data.d.Corpo;
            this.CorpoOriginale = data.d.CorpoOriginale;
            this.CorpoPubblico = data.d.CorpoPubblico;
            this.GruppoPubblicazione = data.d.Gruppo_x0020_di_x0020_pubblicazi;
            this.versioneScheda = data.d.versioneScheda;
            this.pubblicazioneImmediata = data.d.pubblicazione_x0020_immediata;
            this.baseLegale = data.d.BaseLegale;
            this.annoAttivazione = data.d.AnnoDiAttivazione;
            this.annoScadenza = data.d.AnnoDiScadenza;
            this.dataAttivazione = data.d.DataDiAttivazione;
            this.dataScadenza = data.d.DataDiScadenza;
            this.commento1 = data.d.commento1;
            this.commento2 = data.d.commento2;
            this.commento3 = data.d.commento3;
            this.statoSchedaEsterna = data.d.StatoSchedaEsterna;
            this.lookupId = data.d.lookupID; 
            this.tipologia = data.d.Tipo_x0020_Scheda;
            this.tConsultazione = data.d.t_consultazione;
            this.tApprovazione = data.d.t_approvazione;
            this.tAttivazione = data.d.t_attivazione;
            this.referenze = data.d.referenze;
    });
};

Y la llamada sería algo como:

var proposta = new scheda();
var d =  $("#DeltaPlaceHolderPageTitleInTitleArea .die a").html()
proposta.getValori(getParameterByName("ID"),d).then(function() }{ 
  $("#titolo").html(proposta.titolo);
}
Pablo Lozano
  • 45,934
  • 7
  • 48
  • 87