Proyectos de muestra y casos de uso > Caso práctico: 3D-Guided Service Instructions > 3D-Guided Service Instructions 302: Añadir un servicio de ThingWorx sencillo a Vuforia Studio > Llamar a getPriceAvailability y utilizar el vigilante de eventos serviceInvokeComplete
  
Llamar a getPriceAvailability y utilizar el vigilante de eventos serviceInvokeComplete
Una vez que se ha añadido el servicio getPriceAvailability a Vuforia Studio, debe llamarse desde la experiencia para que los datos estén accesibles para la manipulación. Para ello, se debe actualizar el código de 3D-Guided Service Instructions 301. Además, es necesario añadir un vigilante de eventos al código para que la experiencia pueda acceder a los datos de este servicio.
* 
El código completo de esta sección está disponible en Appendix 1 en GitHub.
1. Abra Home.js.
2. En el vigilante de eventos userpick, aplique los siguientes cambios:
a. Borre la variable priceString; ahora se accederá a los datos desde shoppingThing en Vuforia Studio en lugar de accederse a ellos desde los atributos del modelo.
b. Cree un objeto denominado meta y defínalo en el ámbito de la aplicación para que distintas funciones del script puedan acceder a él. Cambie las variables partName, instructionName y partNumber para que sean propiedades del objeto meta.
//
// create an object with the properties below that are based on attribute names from Creo Illustrate for this model. Use metadata.get to obtain the data from the JSON properties for this occurrence.
$scope.meta = {
partName : metadata.get(pathId, 'Display Name'),
instructionName : metadata.get(pathId, 'illustration'),
partNumber : metadata.get(pathId, 'partNumber'),
} // $scope.meta end
c. Borre la variable price y el parámetro de aplicación priceInfo, ya que dependían directamente de la variable priceString.
d. Edite la definición de los parámetros de aplicación itemName y itemNumber para que sean coherentes con la nueva sintaxis para llamar a partName y a partNumber desde el objeto meta. A continuación, cree una variable nueva con el nombre target (en el ámbito de la aplicación) y defínala en la variable targetName del evento userpick.
//
// set itemName app parameter to be equal to the partName variable, same relationship with itemNumber and partNumber and priceInfo and price.
// Set the itemCount to 1 for the purpose of this section, since it is not hooked up to an actual inventory.
$scope.app.params.itemName = $scope.meta.partName;
$scope.app.params.itemNumber = $scope.meta.partNumber;
$scope.app.params.itemCount = 1;

$scope.target = targetName;
e. Añada el siguiente código para activar el servicio getPriceAvailability dentro de shoppingThing. Este código sigue un formato de twx.app.fn.triggerDataService (‘<TWX Entity>’, ‘<TWX Service>’, ‘<parameter>’). La función triggerDataService llama a un servicio proporcionado por ThingWorxVuforia Studio, donde se llama a la entidad y al servicio de ThingWorx, además de a los parámetros de entrada que adopta el servicio. En nuestro caso, la cosa a la que se llama es shoppingThing, que contiene toda la información del artículo, el servicio al que se llama (getPriceAvailability) y el parámetro (pid), que es un parámetro para el número del artículo seleccionado. La salida de este servicio recibe una llamada mediante una llamada asíncrona, que llama al vigilante de eventos serviceInvokeComplete. El vigilante de eventos serviceInvokeComplete se creará más adelante en esta sección.
//
// call the getPriceAvailability ThingWorx service based on partNumber
twx.app.fn.triggerDataService('shoppingThing', 'getPriceAvailability', {pid: $scope.meta.partNumber})
f. La sentencia if de los siguientes elementos emergentes se sacará del vigilante de eventos userpick y se colocará en el vigilante de eventos serviceInvokeComplete. Copie los paréntesis finales de la API de PTC Metadata, la sentencia catch y los paréntesis finales de userpick; a continuación, péguelos debajo del activador del servicio. Asegúrese de borrar el código que acaba de copiar de debajo de la función de desmontaje para el elemento emergente, a fin de no tener paréntesis adicionales.
}) //end brackets for PTC API and .then
//
//catch statement if the promise of having a part with metadata is not met
.catch( (err) => { console.log('metadata extraction failed with reason : ' +err) })
}) //end brackets for userpick function. Will continue to move throughout code
3. Una vez actualizado el vigilante de eventos userpick, procederemos a crear el vigilante de eventos serviceInvokeComplete. Este vigilante de eventos solo se activará cuando el servicio getPriceAvailability se haya completado.
a. Añada el siguiente código para el vigilante de eventos por encima de la sentencia if para el elemento emergente. Seleccione el código desde el principio de la sentencia if hasta el final de la función disassemble, y anule la sangría para alinearlo correctamente.
* 
Habrá una X en un círculo rojo junto a esta línea porque el corchete final para ella aún no se ha creado. Es el comportamiento esperado.
$scope.$on('getPriceAvailability.serviceInvokeComplete', function(evt) {
b. El proceso para llamar al elemento emergente cambiará ahora que los datos se añaden dinámicamente desde ThingWorx. Debajo del vigilante de eventos serviceInvokeComplete, cree una variable denominada rowData, que llamará a la fila actual de la infotable que se ha creado con el servicio getPriceAvailability.
//
// variable holding all data for the current row in the infotable
var rowData = twx.app.mdl['shoppingThing'].svc['getPriceAvailability'].data.current
c. A continuación, cree scripts para determinar cuál es el precio del objeto seleccionado. La variable price utilizará la información de ThingWorx y se definirá en una cadena con el precio de la pieza en la fila seleccionada con un $ delante, o bien ‘UNAVAILABLE’ si la pieza no está disponible. La información que utiliza la variable price se crea mediante un operador condicional que valida que la pieza está disponible antes de verificar su precio. Esto también puede hacerse mediante una sentencia if con las mismas condiciones. Se utiliza una lógica similar para crear el parámetro de aplicación priceInfo que se utiliza para sumar los precios del carro.
//
// price is going to be the variable that is referenced in the popup, while the app parameter priceInfo will be used for adding the total in the cart
var price = rowData.avail === true ? '$' + rowData.price
: 'UNAVAILABLE';
$scope.app.params.priceInfo = rowData.avail === true ? parseFloat(rowData.price)
: undefined ;
d. Cree una variable denominada meta, que se utilizará para colocar el objeto $scope.meta en el vigilante de eventos como objeto local para permitir un acceso fácil a sus valores.
//
// create a variable to bring the $scope.meta object into this event listener as a local object
let meta = $scope.meta
e. Puesto que se añadirá información adicional en el elemento emergente para poder determinar si una pieza está disponible o no en función de la información de shoppingThing, la plantilla del elemento emergente se definirá ahora con una función que se creará más adelante en la actividad. Por lo tanto, borre las condiciones y los paréntesis finales de la sentencia if que se ha creado anteriormente y anule la sangría del código para llamar al elemento emergente.
f. Borre el código del elemento emergente para lo que anteriormente habría sido el caso else de la sentencia if. Además, borre el valor de la propiedad template; se reemplazará en el paso siguiente. Habrá indicadores de error junto a estas líneas de código, pero se resolverán cuando se llene el valor de la plantilla.
g. La propiedad template debe tener un valor que llame a la función setTemplate (que se creará posteriormente) con entradas del objeto meta y la variable price de la pieza seleccionada. El código para llamar al elemento emergente debería coincidir ahora con el código proporcionado a continuación.
//
// adds an ionic popup when a part is clicked
$scope.popup = $ionicPopup.show({
//
//call the function for setting the template
template: $scope.setTemplate(meta, price),
//
// set the scope for the popup
scope: $scope
}); //end of ionic popup
h. Para la función disassemble, deben actualizarse las propiedades model y instruction de modelObject para definir la secuencia de animación del modelo. Aquí es donde se accederá a la variable $scope.target creada con anterioridad, y se actualizará instructionName con la nueva ubicación dentro del objeto meta.
//
// function to be bound to the Disassemble button in the popup
$scope.disassemble = function () {
//
// set an object that targets the model and its instruction property
var modelObject = { model: $scope.targetName,
instruction: 'l-Creo 3D - ' + meta.instructionName + '.pvi' };
//
// set the sequence for the quadcopter to be the name of the associated instruction
$scope.view.wdg.quadcopter.sequence = modelObject.instruction
} //disassemble function end
i. Añada un corchete de cierre y un paréntesis para completar la invocación al servicio getPriceAvailability.
}) // getPriceAvailability end
4. Para agilizar el proceso de usar elementos emergentes de Ionic en su experiencia, es necesario añadir otro vigilante de eventos userpick. Dicho vigilante de eventos se utiliza para cerrar un elemento emergente que no se cerró al pulsar en otra pieza. Cuando se activa, este vigilante de eventos cerrará el elemento emergente de la primera pieza en la que pulsó, y eliminará el sombreador antes de abrir un nuevo elemento emergente y sombrear en la próxima pieza que se seleccione.
//
// userpick event listener that will take place when you click on another part without choosing an option in the popup
$scope.$on('userpick', function (event, targetName, targetType, eventData) {

//
// close the popup and remove the shader from the part even when you didn't chose an option from the popup
$scope.popup.close()

$scope.hiliteOff()

}) // closing userpick end
5. El último paso para actualizar la experiencia es crear la función setTemplate mencionada anteriormente. Esta función se utilizará para definir la variable template que se utilizará en el elemento emergente para determinar la información disponible para la pieza. Esto incluirá la lógica para determinar si hay una secuencia de desmontaje asociada a una pieza y si está disponible en shoppingThing.
a. Debajo de la función clearCart, cree una función denominada setTemplate con entradas de meta y price.
//
// function for setting the template for the Ionic popup
$scope.setTemplate = function (meta, price) {

} // setTemplate end
b. En primer lugar, se añadirá lógica a la función para determinar si hay una secuencia de desmontaje asociada con la pieza seleccionada. La variable instr utiliza un operador condicional para ver si la propiedad instructionName de meta se rellena o no, y asumirá el lugar de la sentencia if que tenía anteriormente. Si hay una secuencia asociada, se creará un botón en el que se puede pulsar para activar la función disassemble, desactivar el sombreador y cerrar el elemento emergente. Si no hay una secuencia asociada, instr se convierte en una cadena vacía.
//
// if there is a disassembly sequence associated with the part, create a Disassemble button in the popup, if not, no button will appear
var instr = meta.instructionName.length > 0 ? '<div class="btndisassemble" ng-click="hiliteOff();popup.close();disassemble();">Disassemble</div>'
: '';
c. Además, debe añadir una lógica para determinar si una pieza está disponible o no. Cree la variable addTo como resultado de un operador condicional que determine si una pieza tiene un precio asociado o no según la información de shoppingThing. Si lo tiene, el precio se muestra en el elemento emergente, junto con un botón Add to Cart en el que se puede pulsar que activa la función addToCart. Si no es así, solo se añade el precio al elemento emergente.
//
// if price != unavailable, define an add to cart button and have the price displayed in the popup, if it is unavailable, just display price
var addTo = price != 'UNAVAILABLE' ? price + '&nbsp; </div><div class="btnadd" ng-click="hiliteOff();popup.close();addToCart();">Add to Cart</div>'
: price ;
d. Una vez determinados los botones disponibles para el elemento emergente, se creará la variable template igual que la que se creó para los elementos emergentes anteriores. El elemento emergente mostrará la cantidad, el número de artículo, el nombre de artículo y el precio del artículo seleccionado, junto con los botones que se aplican al artículo. El botón Continue se añadirá de nuevo para cerrar el elemento emergente. Se añadirá una sentencia RETURN para la variable template, por lo que se generará la salida de la función cuando se ejecute. Esto completará la función setTemplate.
//
// build the template for the popup
var template = '<div>' + $scope.app.params.itemCount + 'x  ' + meta.partNumber +
'&nbsp;</br>' + meta.partName +
'&nbsp;</br>' + addTo + instr +
'<div class="btncontinue" ng-click="hiliteOff();popup.close();">Continue</div>' ;

//
// return the template variable when this function is called
return template
6. Pulse en Vista previa.
a. Pulse en la base del cuadricóptero para ver la opción emergente que incluye una pieza disponible, pero que no tiene ninguna secuencia de desmontaje asociada. Pulse en Continue para cerrar el elemento emergente.
* 
Si no se pulsa en el botón Continue antes de pulsar en otra pieza, los elementos emergentes se agruparán uno encima de otro en lugar de cerrarse el primero.
b. Seleccione uno de los rotores para ver el elemento emergente que muestra una pieza que tiene una secuencia de desmontaje asociada y está disponible.
c. Seleccione la parte superior del cuadricóptero para ver el elemento emergente que muestra una pieza que no tiene ninguna secuencia de desmontaje asociada y no está disponible.
Seleccione cualquiera de los motores para ver el elemento emergente que se muestra cuando una pieza tiene una secuencia de desmontaje asociada, pero no está disponible.
7. Esta sección se ha completado. El resto del código de esta sección es el mismo que el de 3D-Guided Service Instructions 301. Debe poder pulsar en una pieza, aparecer un elemento emergente y se le debe dar una de las cuatro opciones anteriores para un elemento emergente. Y, en su caso, debe poder añadir la pieza al carro. También debe poder buscar piezas con el widget userInput.
En la sección final de este caso práctico, creará el carro de la compra persistente utilizando ThingWorx.