A Tailor Made Native App: Place Orders with 4D for mobile

4D v19 R6 and v19 R7 brought two interesting features to 4D for Mobile. Sessions and displaying web pages served by the 4D server in your native mobile app. But did you think about the possibilities you get when combining them both?

This blog post will show you one of these possibilities. We are going to see how to build a simple app that enables mobile users to place orders with their central purchasing office to consolidate their stock:

Shopping Cart HDI

Feel free to try it yourself with the HDI above 🙂

PROJECT EDITOR SIDE

With this demo app, we are going to see how simple it is to :

  • Add packs to a cart using a primary action and Session storage
  • Visualize the cart using a preset open URL action
  • Give the ability to remove packages from the cart 

 

For that, we need to create two actions from the Action section :

Add To Cart action

First, create an “add To Cart” action, a simple action without any parameters. This action will allow you to send an action request from the mobile device and directly call the On Mobile App Action database method with the necessary context.

To create those actions, you just have to create a new basic action, remove parameters from the parameters bottom table, and select the Current entity scope (as we want to add a specific product to the cart).

open url preset action

We need to create an open URL preset action with a Table scope. Enter the 4D server path in the dedicated field. Let’s enter “/cart.shtml” for instance.

blank

On the Mobile App Action database method

Then click on the Create button to create the On Mobile App Action database method. This will automatically create a Case with all your actions already filled in.

Then, add some code to your On Mobile App Action database method!

  • First, we want to check if stock is left for the products we want to add to the cart.
  • If so, add a product object as a collection item in the Session storage.
  • If the product object already exists in the collection, we want to increment the quantity.
  • Then when the product has been correctly added to the Session storage, we want to decrement the product stock in our database.
  • Finally, we asked the app data to be reloaded.
#DECLARE($request : Object) : Object
var $productExist : Boolean
var $product; $response; $status : Object
var $mobileData : Collection
var $entity : 4D.Entity
$response:=New object
$action:=MobileAppServer.Action.new($request)
Case of 
 : ($request.action="addToCart")  
  If (Session.storage.mobileData=Null)   
   $mobileData:=New shared collection   
   Use (Session.storage)    
    Session.storage.mobileData:=$mobileData    
   End use    
  Else    
   $mobileData:=Session.storage.mobileData   
  End if   
  $entity:=ds[$request.context.dataClass]\
   .query("ID = "+String($request.context.entity.primaryKey))\
   .first()  
  // CHECK IF STOCK > 0
  If ($entity.Stock>0)   
   If ($mobileData.length>0)    
    $product:=$mobileData.query("Name = :1"; $entity.Name).pop()
    $productExist:=$product#Null    
    If ($productExist)     
     Use ($mobileData)      
      $product.Quantity:=$product.Quantity+1
      $product.Price:=($entity.Price)*($product.Quantity)      
     End use      
    End if 
   End if    
   If (Not($productExist))    
    $product:=New shared object(\
     "Name"; $entity.Name; \
     "Picture"; $entity.Picture; \
     "Quantity"; 1; \
     "Price"; $entity.Price)    
    Use ($mobileData)     
     $mobileData.push($product)     
    End use 
   End if    
   $entity.Stock:=$entity.Stock-1
   $status:=$entity.save()   
   If ($status.success)    
    $response.success:=True
    $response.dataSynchro:=True
    $response.statusText:="Well done 👍\n"\
    +$entity.Name+" has been added to your cart!"    
   Else     
    $response.statusText:="Bad luck 🫤\n"\
    +$entity.Name+" has not been added to your cart!"    
   End if    
  Else    
   // STOCK = 0
   $response.dataSynchro:=True
   $response.statusText:="Bad luck 👎\n"\
   +"No more stock available for this product!"   
  End if   
 Else 
  // Unknown action
  $response.statusText:="Unknown action: "+$request.action
End case 
return $response

Then we want to visualize our cart on a web page accessible from our Stocks app screen and give the ability to remove products from the cart.

So let’s have a look at our cart web page…

WEB PAGE

We need to implement several things to display our cart to suit our needs :

  • Get Session.storage.mobileData collection and display one item per table row using 4D tags:
<table id="products">
  <tr>
    <th>Product</th>
    <th>Quantity</th>
    <th>Price</th>
    <th></th>
  </tr>
    <!--#4DEACH $product in Session.storage.mobileData-->
  <tr>
    <td>
      <!--#4DTEXT $product.Name-->
    </td>
    <td>
      <!--#4DTEXT $product.Quantity-->
    </td>
    <td>
      <!--#4DTEXT $product.Price--><b>$</b>
    </td>
    <td>
      <input type="button" value="Delete" onclick="RemoveRecord(this)">
    </td>
  </tr>
  <!--#4DENDEACH-->
</table>
  • Add a javascript function to close the native app view from the webview and call it on the close button click :
<script>
    function closeFunc() {
      $4d.mobile.dismiss();
    }
</script>
  • Add a javascript function to remove a table row (remove a product item from the product collection available in Session. storage) :
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript">
    function RemoveRecord(element) {
      var rowJavascript = element.parentNode.parentNode;
      var rowjQuery = $(element).closest("tr");

      var request = $.ajax({
          method: "POST",
          url: "4DACTION/deleteMethod",
          data: {
              index: rowJavascript.rowIndex - 1
          }
      });
      request.done(function(resultat) {
        window.location.reload();
      });
    }
</script>
  • Finally, we need to create a deleteMethod project method and call it in the RemoveRecord function after having retrieved the index to delete that will allow us to delete an element from the cart and from the Session.storage.mobileData collection:
ARRAY TEXT($var1; 0)
ARRAY TEXT($var2; 0)

WEB GET VARIABLES($var1; $var2)
$indexToRemove:=Find in array($var1; "index")

If ($indexToRemove>0)
	$productIndex:=Num($var2{$indexToRemove})
	
	Use (Session.storage.mobileData)
		$mobileData:=Session.storage.mobileData
		$mobileData.remove($productIndex)
	End use 
End if 

What about Android?

As usual, to get the Android app, you just have to go back to the project editor, select the Android target and click the Build button! You build one single 4D mobile project to get iOS and Android apps. Remember?

Here is the final result on Android :

blank

As you can see, using both the user session and the web pages served by 4D can cover some fascinating use cases!

It’s your turn; share yours with us on the forum! Looking forward to reading your scenario.

David Azancot
• 4D for iOS Product Owner •David Azancot joined the 4D Product team as a Product Owner in 2017. He's in charge of writing the user stories and translating them into functional specifications. His role also includes making sure that feature implementations meet customers' needs.David graduated with an MBA in Marketing, Internet and Mobility from the Leonard De Vinci Institute and began his career in 2011 with a mobile start-up company, later acquired by Madvertise (a mobile marketing group). Passionate about mobile interfaces, he was the natural choice to develop interactive mobile ad formats for the group in 2015. In parallel, David has been developing his own iOS and Android applications since 2012.