Update a read-only column with value while editing

15 posts, 1 answers
  1. Shafi
    Shafi avatar
    43 posts
    Member since:
    Dec 2014

    Posted 07 Jun Link to this post

    Hi!

    I've setup a pure client side grid that does non-batch CRUD on a local array. There is a dropdown cascading involved. After selecting Terminal, the list of Services is filtered. The data that is received for this list by ajax contains the fee of that service. I want that fee value to be taken an update the current new/edit row's fee cell in grid after the selection. Here is what I have so far:

    The Grid and supporting functionality:

    var terminals = [];
    var services = [];
     
    var kendoDataSource = new kendo.data.DataSource({
        data: createRandomData(),
        pageSize: 5,
        schema: {
            model: {
                id: "ParkingServiceId",
                fields: {
                    ParkingServiceId: { type: 'number', editable: false },
                    TerminalId: { type: 'number', validation: { required: true } },
                    ServiceId: { type: 'number', validation: { required: true } },
                    ParkingCardNumber: { type: 'string' },
                    ParkingCardIssueDate: { type: 'date', validation: { required: true } },
                    ParkingCardExpiryDate: { type: 'date', validation: { required: true } },
                    ParkingCardGroup: { type: 'string' },
                    ServiceFee: { type: 'number', validation: { min: 0, required: true } }
                }
            }
        }
    });
     
    var gridMain = $("#serviceDetailsGrid").kendoGrid({
        dataSource: kendoDataSource,
        pageable: false,
        sortable: false,
        toolbar: ["create"],
        columns:
        [
            { field: "ParkingServiceId", width: 90, title: "Id", hidden: true },
            { field: "TerminalId", width: 130, title: "Terminal", template: getTerminalTitle, editor: terminalDropDownEditor },
            { field: "ServiceId", title: "Service", template: getServiceTitle, editor: serviceDropDownEditor },
            { field: "ParkingCardNumber", width: 100, title: "Card #" },
            { field: "ParkingCardIssueDate", width: 112, title: "Issued On", format: "{0:dd-MMM-yyyy}", template: "#= kendo.toString(kendo.parseDate(ParkingCardIssueDate, 'dd-MMM-yyyy'), 'MM/dd/yyyy') #" },
            { field: "ParkingCardExpiryDate", width: 112, title: "Expiry", format: "{0:dd-MMM-yyyy}", template: "#= kendo.toString(kendo.parseDate(ParkingCardExpiryDate, 'dd-MMM-yyyy'), 'MM/dd/yyyy') #" },
            { field: "ServiceFee", editable: false, width: 100, title: "Fee" },
            { command: ["edit", "destroy"], title: " ", width: "200px" }
        ],
        editable: "inline",
        cancel: function (e) { $('#serviceDetailsGrid').data('kendoGrid').dataSource.cancelChanges(); }
    }).data("kendoGrid");
     
    function createRandomData() {
        var data = [];
     
        data.push({
            ParkingServiceId: 1,
            TerminalId: 0,
            ServiceId: 54,
            ParkingCardNumber: 'CARD113',
            ParkingCardIssueDate: parseDateMonthStyle('01-May-16'),
            ParkingCardExpiryDate: parseDateMonthStyle('01-May-17'),
            ParkingCardGroup: 'SomeText1',
            ServiceFee: 940
        });
        data.push({
            ParkingServiceId: 2,
            TerminalId: 1,
            ServiceId: 164,
            ParkingCardNumber: 'CARD114',
            ParkingCardIssueDate: parseDateMonthStyle('01-May-16'),
            ParkingCardExpiryDate: parseDateMonthStyle('01-Nov-16'),
            ParkingCardGroup: 'SomeText2',
            ServiceFee: 470
        });
        data.push({
            ParkingServiceId: 3,
            TerminalId: 2,
            ServiceId: 1554,
            ParkingCardNumber: 'CARD115',
            ParkingCardIssueDate: parseDateMonthStyle('01-May-16'),
            ParkingCardExpiryDate: parseDateMonthStyle('01-Aug-16'),
            ParkingCardGroup: 'SomeText3',
            ServiceFee: 235
        });
     
        return data;
    }
     
    function getTerminalOffline() {
        return terminals;
    }
     
    function setTerminalOffline(setter) {
        console.log("Terminals from cache: " + setter.length);
        terminals = setter;
    }
     
    function getServiceOffline() {
        return services;
    }
     
    function setServiceOffline(setter) {
        console.log("Services from cache: " + setter.length);
        services = setter;
    }
     
    function filterServices(filter) {
        var temp = [];
     
        $.each(getServiceOffline(), function () {
            if ($(this).text.indexOf(filter) > 0) { temp.push($(this)); }
        });
     
        return temp;
    }

    function getTerminalTitle(container, options) {
        var terminalId = container.TerminalId;
     
        for (var i = 0; i < getTerminalOffline().length; i++) {
            if (getTerminalOffline()[i].TerminalId === terminalId) {
                return getTerminalOffline()[i].TerminalName;
            }
        }
     
        return 'N/A (' + getTerminalOffline().length + ")";
    }
     
    function getServiceTitle(container, options) {
        var serviceId = container.ServiceId;
     
        for (var i = 0; i < getServiceOffline().length; i++) {
            if (getServiceOffline()[i].Code === serviceId) {
                return getServiceOffline()[i].NameEnglish;
            }
        }
     
        return 'N/A (' + getServiceOffline().length + ")";
    }
     
    function refreshGrid() {
        gridMain.dataSource.read();
        gridMain.refresh();
    }
     
    $(function () {
        $.post("/Ajax/GetTerminalsCache")
          .done(function (response) {
              if (response.length > 0) {
                  setTerminalOffline(response);
     
                  $.post("/Ajax/GetAllServicesCache")
                    .done(function (response) {
                        if (response.length > 0) {
                            setServiceOffline(response);
                            refreshGrid();
                        }
                    })
                    .fail(function (err) {
                        console.log(err);
                    });
              }
          })
          .fail(function (err) {
              console.log(err);
          });
    });

    The OnChange events:

    function terminalDropDown_OnChange() {
        var companyId = $("#CompanyId").val();
        var terminalId = $("input[id^='terminalsDropDownList']").data("kendoDropDownList").value();
        var serviceDdl = $("input[id^='servicesDropDownList']").data("kendoDropDownList");
     
        serviceDdl.value("");
     
        $.post("/Ajax/GetTerminalServices", { companyId: companyId, terminalId: terminalId })
            .done(function (response) {
                if (response.length > 0) {
                    serviceDdl.setDataSource(response);
                }
            })
            .fail(function (err) {
                console.log(err);
            });
    }

    function serviceDropDown_OnChange(a) {
        var serviceDropDown = $("input[id^='servicesDropDownList']").data("kendoDropDownList");
        var extract = serviceDropDown.dataItem(serviceDropDown.select());
        // I have the fee at extract.Fee
    }

    The above code for terminals updates the services and I'm able to extract Fee from the dataItem of service. Now I want to update the grid current row which can be the first row in case of new record or current edit row. Once I have the the row, I need to access it's dataItem and update the ServiceFee column.

    Issues/questions:

    1. (How to) Even after setting the ServiceFee column of the grid to be not editable, it still is editable
    2. (How to) After going through a lot of questions, all ways to access the current/selected/editing row of grid have failed for me. I'm not able to get the row I want and calling dataItem on what I get results in undefined
    3. Once #2 is solved, is it simple enough to set the grid's current row's dataItem's ServiceFee to Fee?

     

  2. Kostadin
    Admin
    Kostadin avatar
    1711 posts

    Posted 09 Jun Link to this post

    Hello,

    In order to prevent editing of some filed you can set editable to false in the kendo datasource mode.
    model: {
        id: "ParkingServiceId",
        fields: {
            ParkingServiceId: { type: 'number', editable: false },
            TerminalId: { type: 'number', validation: { required: true } },
            ServiceId: { type: 'number', validation: { required: true } },
            ParkingCardNumber: { type: 'string' },
            ParkingCardIssueDate: { type: 'date', validation: { required: true } },
            ParkingCardExpiryDate: { type: 'date', validation: { required: true } },
            ParkingCardGroup: { type: 'string' },
            ServiceFee: { type: 'number', validation: { min: 0, required: true }, editable: false }
        }
    }

    Regards your second question I was unable to understand on which event you are trying to access the data item values. Generally you can hook Edit command which will be fired for both insert and edit, so you can use it to access the dataitem and its values. Please check out the following code snippet.
    edit:function(e){ var productName = e.model.ProductName)},

    If your requirement differs I would appreciate if you can share more information.

    Regards,
    Kostadin
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  3. UI for ASP.NET MVC is VS 2017 Ready
  4. Shafi
    Shafi avatar
    43 posts
    Member since:
    Dec 2014

    Posted 10 Jun in reply to Kostadin Link to this post

    I'll test the editable: false in datasource schema as well.

    The second question is that if you look at my full code above, this is what I'm trying to achieve:

    User selects a terminal and the services dropdown gets populated. The JSON that populates the services dropdown contains a field Fee that I want to pick and use it's value for the ServiceFee of the grid/datasource column for a row currently being edited/inserted.

  5. Shafi
    Shafi avatar
    43 posts
    Member since:
    Dec 2014

    Posted 14 Jun in reply to Shafi Link to this post

    The editable: false in datasource schema has worked nicely.

    The second part of the question is still an open issue for me. Any prompt reply will be greatly appreciated.

  6. Kostadin
    Admin
    Kostadin avatar
    1711 posts

    Posted 14 Jun Link to this post

    Hi Shafi,

    As far as I understand you want to access a Fee fields when editing or inserting a new rows. In such case you can try using the Edit event as mentioned in my previous reply. Additionally you can examine the following sample which elaborates more on Access Editor Controls in Edit Events.

    Regards,
    Kostadin
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  7. Shafi
    Shafi avatar
    43 posts
    Member since:
    Dec 2014

    Posted 15 Jun in reply to Kostadin Link to this post

    Following you link, I was able to hook into the edit event and was able to get a DropDownList and the grid's current model. I was able to manually set the grid model's ServiceFee to a value and it reflected.

    Now, the issue: There are two dropdowns. And the mentioned code selects the first one:

    var serviceDropDownList = container.find("[data-role=dropdownlist]").data("kendoDropDownList");

    How do I select the second dropdown?

  8. Shafi
    Shafi avatar
    43 posts
    Member since:
    Dec 2014

    Posted 15 Jun Link to this post

    I'm attaching the scenario if there is still confusion.

    Issues:

    • I have two DropDownLists
    • DropDownsLists are cascade-locked
    • I need to update the grid's ServiceFee cell EVERY time the selected item in the Service DropDownList is changed

    Following the code you mentioned, I see that the edit event triggers once and as soon as row is added. This behavior is not desired as the Terminal DropDownList needs to be changed to trigger the post-back on Service DropDownList.

    The process of getting the Fee out of Service DropDownList and updating the current row's model doesn't need to be immediate. If it can be done by hooking the Confirm/Update button, I'm OK with that.

    Please help!

  9. Kostadin
    Admin
    Kostadin avatar
    1711 posts

    Posted 16 Jun Link to this post

    Hello Shafi,

    Keep in mind if the selector that you are using match multiple elements you need to loop through them and access the DropDownList widget by using the data method. Otherwise you will get only the first DropDown on the page.
    container.find("[data-role=dropdownlist]").each(function(){
        console.log($(this).data("kendoDropDownList"))
    })

    In case you need to update a cell based on the DropDownList item you can hook up to the select event of the DropDownList editor and use dataItem (grid), closest (jQuery) and set (model) methods. For example:
    select: function() {
        var grid = $("#grid").data("kendoGrid"),
            model = grid.dataItem(this.element.closest("tr"));
     
        model.ProductName = "changed";
    }

    You can check out the following sample which demonstrates that.

    Keep in mind you can use model isNew method to check if the data item is new (created) or not (edited). This way you can execute different logic when inserting or updating an item.

    Regards,
    Kostadin
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  10. Shafi
    Shafi avatar
    43 posts
    Member since:
    Dec 2014

    Posted 18 Jun Link to this post

    Okay, we have almost cracked this one. one last bug: The select event is keeping the last selected value not the current one. So if I make the first selection from "Select service" to a valid value, I get null due to "Select service" being null.

    Second case: Make first selection and then make second selection and leave the dropdownlist. The first selection's Fee will reflect and not the current selection.

  11. Kostadin
    Admin
    Kostadin avatar
    1711 posts

    Posted 21 Jun Link to this post

    Hi,

    In such case you can use a setTimeout function to get the current selected value. Here is a simple code which demonstrates that.
    categoryDropDownList.bind("select", function(e){
      var that= this;
      setTimeout(function(){alert(that.selectedIndex)});
    })

    I hope this information helps.

    Regards,
    Kostadin
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  12. Shafi
    Shafi avatar
    43 posts
    Member since:
    Dec 2014

    Posted 29 Jun in reply to Kostadin Link to this post

    Binding the select event this way didn't trigger at all. Here is what I did:

    function serviceDropDownEditor(container, options) {
        var serviceDropDown =
            $('<input id="servicesDropDownList" required data-text-field="NameEnglish" data-value-field="Code" data-bind="value:' + options.field + '"/>')
                .appendTo(container)
                .kendoDropDownList({
                    optionLabel: "Select service...",
                    autobind: false,
                    dataTextField: "NameEnglish",
                    dataValueField: "Code"
                });
     
        serviceDropDown.bind("select",
            function() {
                var that = this;
                setTimeout(function() {
                    var extract = that.dataItem(serviceDropDown.select());
                    var model = gridMain.dataItem(that.element.closest("tr"));
     
                    model.ServiceFee = extract.Fee;
                }, 100);
            });
    }

    And I also added a 100 ms timeout as well. Still need help.

  13. Kostadin
    Admin
    Kostadin avatar
    1711 posts

    Posted 01 Jul Link to this post

    Hi,

    In case you are hooking the event in the editor template you can directly attach the event to the dropdown. Please try using the following code.
    function serviceDropDownEditor(container, options) {
        var serviceDropDown =
            $('<input id="servicesDropDownList" required data-text-field="NameEnglish" data-value-field="Code" data-bind="value:' + options.field + '"/>')
                .appendTo(container)
                .kendoDropDownList({
                    optionLabel: "Select service...",
                    autobind: false,
                    dataTextField: "NameEnglish",
                    dataValueField: "Code",
                    select: function() {
                        var that = this;
                        setTimeout(function() {
                            var extract = that.dataItem(serviceDropDown.select());
                            var model = gridMain.dataItem(that.element.closest("tr"));
              
                            model.ServiceFee = extract.Fee;
                        }, 100);
                    });
                });
    }

    Here is a sample which demonstrates this approach.

    Regards,
    Kostadin
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  14. Shafi
    Shafi avatar
    43 posts
    Member since:
    Dec 2014

    Posted 11 Jul in reply to Kostadin Link to this post

    Hello again!

    var extract = that.dataItem(serviceDropDown.select())

    Is not returning the correct data model. In fact, it always selects an invalid entry. I have attached an image showing this.

  15. Answer
    Kostadin
    Admin
    Kostadin avatar
    1711 posts

    Posted 13 Jul Link to this post

    Hi Shafi,

    You can use the following approach to access the selected item.
    var extract = that.dataItem(that.selectedIndex);

    I hope this information helps.

    Regards,
    Kostadin
    Telerik by Progress
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  16. Shafi
    Shafi avatar
    43 posts
    Member since:
    Dec 2014

    Posted 13 Jul in reply to Kostadin Link to this post

    That did it! Thanks!
Back to Top
UI for ASP.NET MVC is VS 2017 Ready