Can you detect changes on a List or Library control?

Hi, I have a field in my parent form that is based on the number of child items in my List control (I got this through the _widget._data property in the DataTable fd.control). This works fine when reloading the whole form however I’d like the value to change dynamically so the user can always see the number of items in real time.

I tried using the .$on(‘change’, doFunction) syntax however it is not having any effect.

I see the change,remove and edit functions are available for pure DataTables, but they do not seem to be available for SharePoint List or Library ‘DataTables’ - is there a way of detecting any changes and triggering a function (for example could I attach an event receiver to the DataTable element some other way?)

Kind regards
Andy

Dear Andy,
Currently, no events like this are available. They might be added in the future, as List or Library control will continue to improve in many areas, this has good potential to come in the later versions.

There are some workarounds available currently, it’s just that they are all not perfect.

Hi Nikita

I need the same functionality. Could you perhaps give an update on whether this is planned for implementation or guide me with an example of a workaround?

I want to implement the same as per this post but using a SharePoint list instead of using a Data Table and Flow.

Also requiring the same functionality here. Can you please advise if there are any workarounds in the meantime?

Dear Jack and dear Andre,
Thank you for your requests, we’ll actively work on this feature to be available in future releases.

As for now, a somewhat limited, but a working solution might look like this:

fd.spRendered(function() {
    fd.control('SPDataTable0').ready().then(function(dt) {
        //dt parameter is the same as fd.control('SPDataTable0')
        var currentLength = dt.widget.dataItems().length;
        var intervalTimer = setInterval(checkDT, 1000);

        function checkDT() {
            if(currentLength != dt.widget.dataItems().length){
                alert("Items were added or removed!");
                currentLength = dt.widget.dataItems().length;
            }
        }
    });
});

It’s not perfect, and it will not detect all the changes, but it will detect moments when items are either added or removed.

2 Likes

Dear @JackGilmore and dear @Andre,
Also, anyone else reading the topic. We’ve added a change event to List or Library, which will detect not only deletion or addition of new items, but also edits to the existing items, so you can call it like this:

fd.spRendered(function() {
    fd.control('SPDataTable0').$on('change',
        function() {
            alert('List or Library changed');
        });
});

Please, check it out. And let me know if there are you have any questions or issues at all, I’ll be happy to help.

Hi Nikita

The list control no longer refreshes after adding a new item and leaves the item unbound to the parent item. Even after refreshing the page manually the new items do not appear.
The same applies when editing, however deleting an item works.

Dear Andre,
Please, re-save both parent and child forms, and let me know if the issue remains or if it goes away. There have been some changes, and the code needs to apply to both forms.

Hi Nikita

Redeploying the forms resolved the issue with the page not refreshing.
I am however finding that the change event fires (predictably) before the list data is available, causing the calculation to ignore the latest change to the item. I need it to wait until the data table reflects the updated items before it runs the calculation. Below is my code which I am unable get working and will appreciate your assistance.

fd.spRendered(function() {
    fd.field('Total_x0020_Amount').disabled = true;
    var formatter = new Intl.NumberFormat(fd.culture, {
        style: 'decimal',
        minimumFractionDigits: 2,
    });

    fd.control('SPDataTable0').$on('change',
        function() {
            console.log('List or Library changed');
            **//Need to wait for datatable to be updated**
            var data = fd.control('SPDataTable0').widget._data;
            console.log(data);
            var totalAmount = 0;
            if(data){
                for (var i = 0; i < data.length; i++){
                    totalAmount += Number(parseFloat(data[i].Amount).toFixed(2));
                }
            }
            var amt = parseFloat(totalAmount).toFixed(2);
            console.log(amt);
            fd.field('Total_x0020_Amount').value = formatter.format(amt);
    });
});

Hi Nikita,

Does this just detect changes made through the List or Library Control, or can this detect any changes made in the target list.

My scenario is I have a Display form with a List Control that at the moment I have an interval timer set with a 5 second refresh of the Control so any changes made to the list separate to the control will be still reflected in the control on the Display Form. It would be great if the refresh could be triggered only when changes to the list were detected…

Thanks

Hi Nikita.

I’m trying to solve a similar list refresh issue and could use advice. I’m using jquery to remove the edit and delete icons in each table row if that child list item has ‘been completed’ by checking for a text value in each row. My code below works fine when the form loads, but when the user edits (completes) the child list item and the control refreshes, my function isn’t firing. I tried adding your fd.control(‘SPDataTable0’).$on(‘change’… but not having luck. Do I need to add anything to the child list edit form? Thanks!

function hideEditCompletedRows() {
$("[role=rowgroup] > tr").each(function(){
var fourthCell = $(this).find(“td:eq(4)”).text();
if(fourthCell == ‘Approved’ || fourthCell == ‘Rejected’) {
$(this).find(“td:eq(0)”).html(’’);
$(this).find(“td:eq(1)”).html(’’);
}
});
}

var dt = fd.control(‘SPDataTable0’);
if (dt.widget) {
hideEditCompletedRows();
} else {
dt.$on(‘ready’, function() {
hideEditCompletedRows();
});
}

Dear @Andre, @Tony_Duke, @Bjorn

Guys, I’m terribly sorry, I missed this topic in the community.

For @Andre and @Bjorn:

The cause is the List or Library data table is not bound to the updated data source at that moment.

The solution is to add an event handler to event “dataBound” fired when the widget is bound to data from its data source: https://docs.telerik.com/kendo-ui/api/javascript/ui/grid/events/databound

Like this (@Andre’s issue as an example ):

fd.spRendered(function() {
    fd.control('SPDataTable0').$on('change', function() {   
        fd.control('SPDataTable0').widget.bind("dataBound",function(){
            var data = fd.control('SPDataTable0').widget._data;
            var totalAmount = 0;
            if(data){
                for (var i = 0; i < data.length; i++){
                    totalAmount += Number(parseFloat(data[i].Amount).toFixed(2));
                }
            }
            var amt = parseFloat(totalAmount).toFixed(2);
            console.log(amt);
            fd.field('Sum').value = amt;
        })
    });
})

For @Tony_Duke:

“Change” event detects only changes in the List/Library control widget. To handle List events you can utilize PnP and workflow: https://docs.microsoft.com/en-us/sharepoint/dev/sp-add-ins/handle-events-in-sharepoint-add-ins#HandlingAppEvents

1 Like

Thanks Aleksey, that worked for me!

hi i am able to get the item changed fire but total field shows as NAN
and when i alert amt nothing shows up

i have parse float set it alerts at table changed but data i dont get any alert. Thank you.
fd.spRendered(function() {
//alert("rendered");
fd.control('SPDataTable1').$on('change', function() {
//alert("datatable changed"); //here works
fd.control('SPDataTable1').widget.bind("dataBound",function(){
var data = fd.control('SPDataTable1').widget._data;
alert(data); //nothing here
var TotalAmount = 0;
if(data){
for (var i = 0; i < data.length; i++){
TotalAmount += Number(parseFloat(data[i].Amount).toFixed(2));
}
}
var amt = parseFloat(TotalAmount).toFixed(2);
alert(amt);
fd.field('Totalcost').value = amt;
})
});
})

i figured it out thank you but the issue now is it works sometime and sometime it doesnt