Search code examples
javascriptc#htmlknockout.jsdevextreme

How to get data from master view to detail view


I have an image to illustrate my question
I'm using devextreme, html, js(knockout), c#, odata This is my code :

order-details.dxview

<div data-options="dxView : { name: 'OrderDetail', title: 'Order' } " >
<div data-bind="dxCommand: { onExecute: '#OrderEdit/{id}', direction: 'none', id: 'edit', title: 'Edit', icon: 'edit' }"></div>
<div data-bind="dxCommand: { onExecute: handleDelete, id: 'delete', title: 'Delete', icon: 'remove' }"></div>
<div  data-options="dxContent : { targetPlaceholder: 'content' } " class="dx-detail-view dx-content-background" data-bind="dxDeferRendering: { showLoadIndicator: true, staggerItemSelector: 'dx-fieldset-header,.dx-field', animation: 'detail-item-rendered', renderWhen: isReady }" >
    <div data-bind="dxScrollView: { }">
        <div class="dx-fieldset">
            <div class="dx-fieldset-header" data-bind="text: order.PhoneNumber"></div>
            <div class="dx-field">
                <div class="dx-field-label">Order id</div>
                <div class="dx-field-value-static" data-bind="text: order.OrderId"></div>
            </div>
            <div class="dx-field">
                <div class="dx-field-label">Phone number</div>
                <div class="dx-field-value-static" data-bind="text: order.PhoneNumber"></div>
            </div>
            <div class="dx-field">
                <div class="button-info" data-bind="dxButton: { text: 'Add Item', onClick: '#AddItem/{order.OrderId}', icon: 'add', type: 'success' }"></div>
                <!-- Item List -->
                <div data-bind="dxList: { dataSource: dataSource, pullRefreshEnabled: true }">
                    <div data-bind="dxAction: '#OrderDetailDetails/{OrderDetailId}'" data-options="dxTemplate : { name: 'item' } ">
                        <!--<div class="list-item" data-bind="text: Item().ItemName"></div>
                        <div class="list-item" style="float:right;" data-bind="text: Amount"></div>-->
                        <div class="item-name" data-bind="text: Item().ItemName"></div>
                        <div class="item-amount" data-bind="text: Amount"></div>
                        <div class="clear-both"></div>
                    </div>
                </div>
            </div>
            <div class="dx-field">
                <div class="dx-field-label">Grand total</div>
                <div class="dx-field-value-static" data-bind="text: order.GrandTotal"></div>
            </div>
        </div>
        <div data-options="dxContentPlaceholder : { name: 'view-footer', animation: 'none' } " ></div>
    </div>
</div>

order-details.js

POSApp.OrderDetail = function(params, viewInfo) {
    "use strict";

    var id = params.id,
        order = new POSApp.OrderViewModel(),
        isReady = $.Deferred(),
        // Item List
        shouldReload = false,
        dataSourceObservable = ko.observable(),
        dataSource;

    function handleDelete() {
        DevExpress.ui.dialog.confirm("Are you sure you want to delete this item?", "Delete item").then(function(result) {
            if(result)
                handleConfirmDelete();
        });
    }

    function handleConfirmDelete() {        
        POSApp.db.Orders.remove(id).done(function() {
            if(viewInfo.canBack) {
                POSApp.app.navigate("Orders", { target: "back" });
            }
            else {
                POSApp.app.navigate("Blank", { target: "current" });
            }
        });
    }

    function handleViewShown() {
        POSApp.db.Orders.byKey(id).done(function(data) {
            order.fromJS(data);
            isReady.resolve();
        });

        //Item List
        if (!dataSourceObservable()) {
            dataSourceObservable(dataSource);
            dataSource.load().always(function () {
                isReady.resolve();
            });
        }
        else if (shouldReload) {
            refreshList();
        }
    }

    //Item List

    function handleOrderDetailsModification() {
        shouldReload = true;
    }

    function handleViewDisposing() {
        POSApp.db.OrderDetails.off("modified", handleOrderDetailsModification);
    }

    function refreshList() {
        shouldReload = false;
        dataSource.pageIndex(0);
        dataSource.load();
    }

    dataSource = new DevExpress.data.DataSource({
        store: POSApp.db.OrderDetails,
        map: function (item) {
            return new POSApp.OrderDetailViewModel(item);
        },
        expand: ["Item"],
        sort: { field: "OrderDetailId", desc: false },
        filter: ["OrderId", parseInt(id)]
    });

    POSApp.db.OrderDetails.on("modified", handleOrderDetailsModification);

    //Item List

    return {
        id: id,
        order: order,
        handleDelete: handleDelete,        
        viewShown: handleViewShown,
        isReady: isReady.promise(),
        //Item List
        dataSource: dataSourceObservable,
        refreshList: refreshList,
        viewDisposing: handleViewDisposing,
    };
};

add-item.dxview

<div data-options="dxView : { name: 'AddItem', title: 'Add Item' } " >
    <div data-bind="dxCommand: { onExecute: handleSave, id: 'save', title: 'Save', icon: 'save' } "></div>
    <div data-bind="dxCommand: { onExecute: handleCancel, id: 'cancel', behavior: 'back', title: 'Cancel', icon: 'close' }"></div>
    <div data-options="dxContent : { targetPlaceholder: 'content' } " class="dx-edit-view dx-content-background dx-form-background" data-bind="dxDeferRendering: { showLoadIndicator: true, staggerItemSelector: '.dx-field', animation: 'edit-item-rendered', renderWhen: isReady }">
        <div data-bind="dxScrollView: { }">
            <div class="dx-fieldset">
                <div class="dx-field">
                    <div class="dx-field-label">Order detail id: </div>
                    <div class="dx-field-value" data-bind="dxNumberBox: { value: orderdetail.OrderDetailId, readOnly: true }"></div>
                </div>
                <div class="dx-field">
                    <div class="dx-field-label">Order Id: </div>
                    <div class="dx-field-value" data-bind="dxLookup: { dataSource: ordersSource, value: orderdetail.Order, displayExpr: 'PhoneNumber', title: 'Orders', placeholder: 'Choose Order' }"></div>
                    <!--<div class="dx-field-value" data-bind="dxNumberBox: { value: orderdetail.Order, placeholder: 'Enter Order Id' }"></div>-->
                </div>
                <div class="dx-field">
                    <div class="dx-field-label">Item: </div>
                    <div class="dx-field-value" data-bind="dxLookup: { dataSource: itemsSource, value: orderdetail.Item, displayExpr: 'ItemName', title: 'Items', placeholder: 'Choose Item' }"></div>
                </div>
                <div class="dx-field">
                    <div class="dx-field-label">Quantity: </div>
                    <div class="dx-field-value" data-bind="dxNumberBox: { value: orderdetail.Quantity, placeholder: 'Enter Quantity' }"></div>
                </div>
                <div class="dx-field">
                    <div class="dx-field-label">Price: </div>
                    <div class="dx-field-value" data-bind="dxNumberBox: { value: orderdetail.Price, placeholder: 'Enter Price' }"></div>
                </div>
                <div class="dx-field">
                    <div class="dx-field-label">Amount: </div>
                    <div class="dx-field-value" data-bind="dxNumberBox: { value: orderdetail.Amount, placeholder: 'Enter Amount' }"></div>
                </div>
            </div>
        </div>
    </div>
</div>

add-item.js

POSApp.AddItem = function (params, viewInfo) {
    "use strict";

    var id = params.id,
        isNew = (id === undefined),
        isSplitLayout = viewInfo.layoutController.name === "split",
        orderdetail = new POSApp.OrderDetailViewModel(),
        isReady = $.Deferred();

    orderdetail.Order(parseInt(id));
    //orderdetail.Order(new POSApp.OrderViewModel(id));
    alert(parseInt(id));

    function load() {
        return POSApp.db.OrderDetails.byKey(id, { expand: ["Item"] }).done(function (data) {
            orderdetail.fromJS(data);
        });
    }

    function insert() {
        // Insert Code
        POSApp.db.OrderDetails.insert(orderdetail.toJS()).done(function (values, newId) {
            //POSApp.app.navigate({ view: "order-details", id: params.id }, { target: "back" });
            POSApp.app.back();
            orderdetail.clear();
        });
    }

    function handleSave() {
        insert()
        //orderdetail.clear();
        //POSApp.app.back();
        // Go back to order-edit and the item that have been chosen will be displayed in the order-edit
        // And so on for the next item
    }

    function handleCancel() {
        orderdetail.clear();
        POSApp.app.back();
    }

    function handleViewShown() {
        isReady.resolve();
    }

    return {
        orderdetail: orderdetail,
        ordersSource: {
            store: POSApp.db.Orders,
            map: function(data) {
                return new POSApp.OrderViewModel(data);
            }
        },
        itemsSource: {
            store: POSApp.db.Items,
            map: function (data) {
                return new POSApp.ItemViewModel(data);
            }
        },
        handleSave: handleSave,
        handleCancel: handleCancel,
        viewShown: handleViewShown,
        isReady: isReady.promise()
    };

};

What I'm asking is how to pass the id of the order to the add item view properly? because with this code, when I save it, in the database the orderid is null, so there's no value inserted. But in the add item view, in the order lookup filed, the id or value was there but it wont be inserted to the database.

Many Thanks & Best Regards Michael Reno


Solution

  • To pass a parameter to a view you can use the app.navigate() method with args you need:

    MyApp.app.navigate({
       view: "home",
       id: YOUR_ID
    });
    

    In this case, the id field will be available on the 'home' view:

    MyApp.home = function (params) {
        var id = params.id;
    };
    

    See more information about a navigation between views in this tutorial as well.

    Hope this information will be helpful for you.

    P.S. there are a lot of useful tutorials about the DevExtreme SPA Framework here.

    UPD

    I've created a simple project here. It shows how to pass params between views in action.