This feature was introduced in version 4.80.0 of the JourneyApps Runtime and version 21.3.2 of the JourneyApps Container.
It is currently only supported on iOS and Android devices.
Photo quality
When using multiple photo capture, photos are stored at 85% quality by default. If you wish to take and display more than 5 photos at a time, please set the quality down to below 25%, which corresponds approximately with the default quality for capture-photo.
This feature allows an app user to take multiple photos in quick succession from the app.
Taking multiple photos in a single workflow works slightly different from the capture-photo UI component. The biggest difference is that there isn't an XML component and that there isn't a variable or field that the resulting photos are automatically bound to.
Instead, the developer calls a function that can be triggered from anywhere, e.g. a button or object-table, and the function returns an array of image attachments that the developer can use however they prefer.
Syntax
journey.photos.capture(options), where options are optional:
The resulting array of attachments can be used by the developer however they prefer. If the user cancels the camera without taking any photos, the function will return an empty array.
Note: Multiple photos is currently only supported on mobile devices, and support for this feature can be evaluated for a device as follows:
journey.photos.getCapabilities(). This will return an object:
{"supported":true | false}
Example
In this basic example, we have a button that allows a user to take 10 photos in a single flow. The photos are then added to an array that is displayed in a List component that triggers a Dialog that has a display-photo component and some buttons to delete the photo.
The user will also be able to add more photos by clicking the button again, and new photos will be added to the top of the list in this example.
Firstly, we create a new model in the app's Data Model to store the photos:
<!-- temporary placeholder to store the image for the dialog--><varname="dialog_photo"type="multi_photo" /><!-- query for the list component--><varname="photos"type="array:multi_photo" /><!-- Button to trigger the capture--><buttonlabel="Take photos"on-press="$:takePhotos()"validate="false"style="solid" /><!-- column container list component to show a preview of photos taken--><listempty-message="Your photos will appear here"show-if="$:showList()"> <list-itemquery="photos"on-press="$:pressed($selection)"> <header>Edit/change</header> <assetsrc="{$:getImage($object)}" /> </list-item></list><!-- dialog to show the selected photo and delete--><dialogid="edit-photos"title="Edit"><body> <display-photobind="dialog_photo.image"downloadable="true" /> </body> <button-group> <buttonlabel="Cancel"color="negative"on-press="$:onCancel()"validate="false"/> <buttonlabel="Delete"on-press="$:deletePhoto()"validate="false"/> </button-group></dialog>
In the corresponding JavaScript/TypeScript for the view:
functioninit() {view.photos = [];}functiontakePhotos() {var capabilities =journey.photos.getCapabilities();if (capabilities.supported !=true) {awaitjourney.dialog.error({ title:"Multiple photos are not supported on Desktop and Web." });return; }// capture maximum 10 photos at 25% quality.var photos =journey.photos.capture({max:10, quality:25});for (var i =0; i <photos.length; i++) {// We create a LocalDB entry in this example for each photo.// Note that `multi_photo` is the name we// used in the Data Model in this example.var newPhotoEntry =LocalDB.multi_photo.create();newPhotoEntry.image = photos[i];newPhotoEntry.save();// .unshift adds entries to the front of the array.// Can use .push to add to the back of the array.view.photos.unshift(newPhotoEntry); }// Since we are altering the view.photos array,// we force a digest just to be sure// that the UI is updated correctly.journey.forceDigest();}// This gets the image from the model so that it can be displayedfunctiongetImage(object) {returnobject.image;}functiononCancel() {component.dialog({id:'edit-photos'}).hide();}// When a photo is clicked from the List componentfunctionpressed(element) {view.dialog_photo = element;component.dialog({id:'edit-photos'}).show();}functiondeletePhoto() {var id =view.photos.indexOf(view.dialog_photo);view.photos.splice(id,1);}functionshowList() {returnview.photos.length>0;}
functioninit() {view.photos = [];}asyncfunctiontakePhotos() {var capabilities =awaitjourney.photos.getCapabilities();if (capabilities.supported !=true) {awaitjourney.dialog.error({ title:"Multiple photos are not supported on Desktop and Web." });return; }// capture maximum 10 photos at 25% quality.var photos =awaitjourney.photos.capture({max:10, quality:25});for (let photo of photos) {// We create a LocalDB entry in this example for each photo.// Note that `multi_photo` is the name we// used in the Data Model in this example.let newPhotoEntry =LocalDB.multi_photo.create();newPhotoEntry.image = photo;awaitnewPhotoEntry.save();// .unshift adds entries to the front of the array.// Can use .push to add to the back of the array.view.photos.unshift(newPhotoEntry); }// Since we are altering the view.photos array,// we force a digest just to be sure// that the UI is updated correctly.journey.forceDigest();}// This gets the image from the model so that it can be displayedfunctiongetImage(object) {returnobject.image;}functiononCancel() {component.dialog({id:'edit-photos'}).hide();}// When a photo is clicked from the List componentfunctionpressed(element) {view.dialog_photo = element;component.dialog({id:'edit-photos'}).show();}functiondeletePhoto() {let id =view.photos.indexOf(view.dialog_photo);view.photos.splice(id,1);}functionshowList() {returnview.photos.length>0;}
Optional maximum number of photos to be taken. Defaults to undefined that means no limit. If the max number is reached, the camera dialog is automatically closed and the function returns.
quality
Optional number between 1 and 100 to set the quality of the resulting images. Defaults to 85. The equivalent of medium resolution photos for capture-photo is around 25, and is recommended for most use cases.