Sample List of Products for an Order

Sample List of Products for an Order
We've created a sample HTML5 document that can be opened within Mobile CRM application. It is a list
of products associated with an order. Order DetailsForm now contains one more tab of type
IDocumentView. OrderDetails.htm file is then displayed on the IFrame of DocumentView.
When the document is opened, it loads a list of all products using Resco JavaScriptBridge and
fetch.execute() method. Products are presented to user through our custom JavaScript control,
AdvancedList. User can click on a product listed in the AdvancedList and modify the amount of products
associated with an Order by clicking/taping the Add or Remove buttons.
For purpose of this sample, we decided to use JQueryMobile to simplify the process of designing the
page.
Let’s take a look at the structure of html document and a few lines of JavaScript code, providing the
whole functionality of the page.
First, we include references to JavaScript libraries to the head section of the html document:
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" />
<script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script>
<script src="advancedList.js"></script>
<script src="JSBridge.js"></script>
Then the html document alone. It is really simple. As we are using JQueryMobile, the most of the work is
done by the JQueryMobile library itself. The largest part of the html structure is definition of two
templates that we will use for AdvancedList control. One template is for selected item of the list, the
second is the general template for all the other items listed.
<div id="mainPage" data-role="page">
<div class="content" />
<!-- template for AdvancedList -->
<div id="person-unselected" data-list-template="person-template">
<table>
<tr>
<td style="width: 50px; text-align: center">
<span id="quantity" data-source-member="3"></span>
</td>
<td width="*" style="vertical-align: top; padding-left: 20px">
<span data-source-member="0"></span><br />
<br />
<p style="font-size: 14px">
Price: <span data-source-member="1" style="font-weight: bold"></span> $
<br />
</p>
</td>
</tr>
</table>
</div><!-- /template -->
<!-- selected template for AdvancedList -->
<div id="person-selected" data-list-template="person-template">
<table>
<tr>
<td style="width: 50px; text-align: center">
<span id="quantity" data-source-member="3"></span>
</td>
<td width="*" style="vertical-align: top; padding-left: 20px">
<span data-source-member="0"></span><br />
<br />
<p style="font-size: 14px">
Price: <span data-source-member="1" style="font-weight: bold"></span> $
<br />
</p>
</td>
</tr>
<tr>
<td></td>
<td style="padding-left: 15px">
<div data-role="controlgroup" data-type="horizontal" data-mini="true" style="padding-top: 15px">
<a data-role="button" data-icon="plus" data-listbutton="true" data-buttonname="add">Add</a>
<a data-role="button" data-icon="minus" data-listbutton="true" databuttonname="remove">Remove</a>
</div>
</td>
</tr>
</table>
</div><!-- /selected template -->
</div><!-- /page -->
Last but not least, there are 3 methods written in JavaScript:
- LoadDataSource method loads the data from CRM and sets it as a datasouce for JavaScript
AdvancedList control.
- ProductBtnClicked method handles the clicks on Add/Remove buttons, so the number of products for
order is immediately reflected in the order entity
- Initialize method
Initialize method:
1. get the templates from html DOM using JQuery
var template = $("#person-unselected");
var selectedTemplate = $("#person-selected");
2. Instantiate and initialize the list control. Add templates to the list, set the index of the selected
template and initialize a filter
productList = new advancedList("list-people", false);
productList.addTemplate(template);
productList.addTemplate(selectedTemplate);
productList.selectedTemplateIndex = 1;
productList.useFilter = true;
productList.filterPlaceholder = "Type product name to filter products...";
3. Assign event handlers. One for button clicks and one for row validating. Row validating event is
fired each time the data are bound to the item. You can modify the value that is finally
presented to the user. In this case, when the quantity property of product entity is zero, no digit
is shown.
productList.listButtonClicked = productBtnClicked;
productList.rowDataValidating = function(data, dataSourceMember){
if (dataSourceMember == 3 && data == 0){
return "";
}
}
4. Add the list control to the DOM and hide the template definitions
productList.appendTo($(".content"));
// hide templates defined in html
template.hide();
selectedTemplate.hide();
5. If ownerID is in correct format, call loadDataSource method in #mainPage init event. Also handle
the size of the list there.
var ownerId = location.search;
if (ownerId != null && ownerId.length > 32) {
$('#mainPage').live('pageinit', function(event){
ownerId = ownerId.replace('?', '')
loadDataSource(ownerId);
$("#mainPage").width($(window).width() - 40);
});
}
$(window).resize(function() {
$("#mainPage").width($(window).width() - 40);
});
LoadDataSource method:
As mentioned in the 'Implementing the CRM Fetch request from Javascript' section (refer to the
MobileCRM documentation), we call bridge methods to get the data. For more info refer to that section.
In this case we are interested in product entities, we want attributes 'name', 'price', 'productId' and
from linkedentity salesorderdetails we need quantity attribute. In Callback of fetch.execute() method,
we simply set the data obtained ,as a datasource of our list.
function loadDataSource(orderId) {
// fetch the data
var fetch = new MobileCRM.FetchXml.Fetch();
var entity = new MobileCRM.FetchXml.Entity("product");
fetch.entity = entity;
entity.attributes = [new MobileCRM.FetchXml.Attribute('name'),
new MobileCRM.FetchXml.Attribute('price'),
new MobileCRM.FetchXml.Attribute('productid')];
entity.order = [new MobileCRM.FetchXml.Order('name')];
if (orderId != null && orderId.length > 32) {
var linkentity = new MobileCRM.FetchXml.LinkEntity("salesorderdetail");
linkentity.attributes = [new MobileCRM.FetchXml.Attribute('quantity')];
linkentity.from = "productid";
linkentity.to = "productid";
linkentity.linktype = "outer";
linkentity.filter = { conditions: [{ attribute: "salesorderid", operator:
"eq", value: orderId}] };
entity.linkentity = [linkentity];
}
fetch.execute(function (res) { window.productList.setDataSource(res); },
function (err) { alert(err); }, null);
}
ProductBtnClicked method:
When a user selects an item from the list, they can click on the add or remove buttons to set the
amount of products for an order. This is handled in productBtnClicked callback. When the amount
changes, we simply change the label showing the number of products selected and using Mobile CRM
bridge we notify the Mobile CRM that the amount of products has changed.
function productBtnClicked(data, senderName, template) {
var qnty = data[3] === undefined ? 0 : data[3];
if (senderName === "add") {
qnty++;
}
else if (qnty > 0) {
qnty--;
}
data[3] = qnty;
var txtQnty = qnty == 0 ? "" : qnty;
$("#quantity", template).text(txtQnty);
MobileCRM.bridge.command("setProductQuantity", data[2] + ":" + qnty);
}
That’s it. As you can see, the implementation of this html form for picking products was easy using Resco
Mobile CRM Bridge. Go, try it by yourself—with HTML5 and JavaScript, you can greatly improve the
visual appearance of the Mobile CRM application.