We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. (Last updated on: June 24, 2019).
Unfortunately, activation email could not send to your email. Please try again.
Syncfusion Feedback

How to change Paging after batch update

Thread ID:

Created:

Updated:

Platform:

Replies:

147016 Aug 28,2019 10:36 PM UTC Sep 11,2019 11:45 AM UTC ASP.NET Core 13
loading
Tags: Grid
Chris
Asked On August 28, 2019 10:36 PM UTC

Hi,

I have a grid where the edit mode is Batch. I am using "url" datasource and a "batch url" for CRUD operations.

In the data source method I am sorting my list before the usual Syncfusion "DataOperations" code.

For example:

List<mythings> mythings = _context.mythings.Where(w => w.DeletionDate == null).OrderBy(o => o.Sort).ToList();

IEnumerable data = mythings;

DataOperations operation = new DataOperations();
if (dm.Sorted != null && dm.Sorted.Count > 0) //Sorting
{
    data = operation.PerformSorting(data, dm.Sorted);
 }
 if (dm.Where != null && dm.Where.Count > 0) //Filtering
 {
         data = operation.PerformWhereFilter(data, dm.Where, dm.Where[0].Operator);
  }

Etc.

Because of the sorting that I do in the datasource method; after saving and refreshing; the inserted record may not be on the current grid page.

For example:
1) Let's say the grid has 50 pages
2) The user is on page 1 of the grid
3) The user inserts a new record and saves.
4) The refreshed grid is on page 1 but the newly added record is on page 4.

How can I get the grid to go to page 4 (or whatever page it ends up on) when it refreshes?  I need to do something so that the user doesn't have to search for the record they just added. (I realize that in batch mode they could have added more then one, I'll just do this for first added record). 

Thanks,
Chris


Chris
Replied On August 29, 2019 02:57 PM UTC

Hi,

My grid has the following in the setup:

<e-datamanager url="MyDataSource" batch-url="MyBatchUpdate" adaptor="UrlAdaptor" />

I noticed that when I save the following happens:

1) "MyBatchUpdate" method runs
2) Then, "MyDataSource" method runs

How can I pass a parameter from "MyBatchUpdate" to "MyDataSource"?  If I could do that, I am pretty sure I could figure out something to meet my requirement.

Thanks,
Chris

Chris
Replied On August 29, 2019 10:14 PM UTC

Hi,

I ALMOST have this working.  I am able to get the grid to go to the correct page.  However, I need a way to manually refresh or change the paging information at the bottom of the page. 

For example:
1) Let's say we are on page 2 of the grid.  A new record is inserted and saved.
2) The new record ends up on page 10 of the grid.  After the record is saved the grid does show page 10.
3) However, the paging information at the bottom of the grid is not updated.  It still has the "2" button highlighted and says "2 of 36 pages".  I need to update it somehow have the "10" button highlighted and to say "10 of 36 pages".

Can you help me achieve that?

For some background, here is how I am getting the grid to go to the correct page after saving:

public ActionResult BatchUpdate([FromBody]SubmitValue myObject) {
   TempData["NewId"] = 1;

    if (myObject.Added != null && myObject.Added.Count > 0) {
       foreach (var insObj in myObject.Added) {
           // code to add a new object
           TempData["NewId"] = insObj.Id;
       }
    }

   // etc
}

public IActionResult DataSource([FromBody]DataManager dm) {
    List mythings = _context.mythings.Where(w => w.DeletionDate == null).ToList();

    var newId = TempData["NewId"];

    IEnumerable data = mythings;

            DataOperations operation = new DataOperations();
           
            if (dm.Sorted != null && dm.Sorted.Count > 0) //Sorting
            {
                data = operation.PerformSorting(data, dm.Sorted);
            }
            if (dm.Where != null && dm.Where.Count > 0) //Filtering
            {
                data = operation.PerformWhereFilter(data, dm.Where, dm.Where[0].Operator);
            }

           int count = data.Cast().Count();

            if (newId != null)
            {
                string newIdStr = Convert.ToString(newId);
                if (newIdStr.IsStringInteger())
                {
                    int newIdVal = Convert.ToInt32(newIdStr);
                    if (newIdVal > 1)
                    {
                        var skipItems = data.Cast().ToList();
                        int skipIdx = skipItems.FindIndex(f => f.Id == newIdVal);
                        decimal skipFraction = skipIdx / dm.Take;
                        int pageNum = Convert.ToInt32(Math.Floor(skipFraction)) + 1;
                        int skipVal = (pageNum - 1) * dm.Take;
                        if (skipVal >= 0)
                        {
                            dm.Skip = skipVal;
                        }
                    }
                }

            if (dm.Skip != 0)
            {
                data = operation.PerformSkip(data, dm.Skip);
            }
            if (dm.Take != 0)
            {
                data = operation.PerformTake(data, dm.Take);
            }

            //etc

            }
}

Thanks,
Chris

Padmavathy Kamalanathan [Syncfusion]
Replied On August 30, 2019 01:19 AM UTC

Hi Chris, 

Sorry for the delay. 

QUERY: I need a way to manually refresh or change the paging information at the bottom of the page. 

We have validated your query. We are able to reproduce the reported issue at our end. We will update the solution for this query shortly. 

Till then we appreciate your patience. 

Regards, 
Padmavathy Kamalanathan  


Padmavathy Kamalanathan [Syncfusion]
Replied On August 30, 2019 10:18 AM UTC

Hi Chris, 

Thanks for your patience. 

We have validated your query. You have reported that you are able to get the correct page you need and can be able to navigate to it. But your grid pager shows previous page number.  

You have performed page navigation operations at the server side. We suggest you to pass the page number to client side, and in client side(view page), you can navigate to a particular page using gotoPage method in actionComplete event with requestType as batchsave. 
 

<ej-grid id="FlatGrid" allow-paging="true" action-complete="complete" allow-sorting="true"> 
  <e-columns> 
     -------- 
  </e-columns> 
</ej-grid> 


<script > 
             
  function complete(args) { 
      if (args.requestType == "batchsave") { 
// get the page number from server side and pass it as parameter to gotoPage method 
          this.gotoPage(page); 
      } 
  } 
</script> 
 




Please refer the below help documentation, 

If you have further queries, please get back to us. 

Regards, 
Padmavathy Kamalanathan 


Chris
Replied On August 30, 2019 07:57 PM UTC

Thank you for the reply.

1) It works, but the gotoPage command invokes the "DataSource" method again.  Is there a way to do this without creating an extra trip to the server?
2) To get what the current page should be, I set a session variable in the Datasource method.  In the "action-complete" javascript I use AJAX to get what the current page should be.  Is there a better way to do this using Syncfusion controls?
3) My coworker and I have been noticing for the past few days that the navigation on the left hand side of the Syncfusion Javascript API page isn't working.  It just shows the spinner.  Could this get corrected?  It makes it hard to find things.

Thanks,
Chris

Padmavathy Kamalanathan [Syncfusion]
Replied On September 5, 2019 05:42 PM UTC

Hi Chris, 

Sorry for the delay. 

QUERY: How to change page after batch update 

We have achieved your query by extending the url adaptor to custom adaptor in load event of grid. Get the current page of edited record in server side, also set skip take value and get the data from server side. In client side, you can get the data and page number. Save that number in window variable, and in actionComplete event with requestType as “batchSave”, get the pager element , and change the currentpage of pager element( with class name e-active). Also set the current page of pageSetting from the grid instance. 

Thus you can achieve your requirement. 

Please check the below code, 


 
        public static List<Order> orddata = new List<Order>(); 
        public static List<Order> sorteddata = new List<Order>(); 
        //initially set id to -1  
        id = -1; 
 
 
        public ActionResult DataSource([FromBody]DataManager dm) 
        { 
            IEnumerable data = orddata; 
            
            DataOperations operation = new DataOperations(); 
            if (dm.Sorted != null && dm.Sorted.Count > 0) //Sorting 
            { 
                data = operation.PerformSorting(data, dm.Sorted); 
                sorteddata = data.Cast<Order>().ToList(); 
            } 
            if (dm.Where != null && dm.Where.Count > 0) //Filtering 
            { 
                data = operation.PerformWhereFilter(data, dm.Where, dm.Where[0].Operator); 
            } 
            int count = data.Cast<Order>().Count(); 
 
            if(!(id.Equals(-1))) 
            { 
                // find the element that is edited first  
                var value = sorteddata.FindIndex(orddata => orddata.OrderID == id); 
                decimal frac = value / dm.Take; 
                int num = Convert.ToInt32(Math.Floor(frac)) + 1; 
                page = num; //page number of first edited record 
                int skipValue = (page - 1) * dm.Take; 
                if (skipValue >= 0) 
                { 
                    dm.Skip = skipValue; 
                    data = operation.PerformSkip(data, dm.Skip); 
                    data = operation.PerformTake(data, dm.Take); 
                    int count = data.Cast<Order>().Count(); 
 
                } 
            } 
            else 
            { 
                if (dm.Skip != 0) 
                { 
                    data = operation.PerformSkip(data, dm.Skip); 
                } 
                if (dm.Take != 0) 
                { 
                    data = operation.PerformTake(data, dm.Take); 
                } 
                int count = data.Cast<Order>().Count(); 
                page = 1; 
            } 
 
            return Json(new { result = data, count = count, currentPage = page }); 
 
        } 
        public ActionResult BatchUpdate([FromBody]submitvalue myObject) 
        { 
            if (myObject.Changed != null && myObject.Changed.Count > 0) 
            { 
                foreach (var temp in myObject.Changed) 
                { 
                    var ord = temp; 
                    Order val = orddata.Where(or => or.OrderID == ord.OrderID).FirstOrDefault(); 
                } 
           // get the primarykey of first edited record from myObject.Changed 
                id = (long)myObject.Changed[0].OrderID; 
            } 
            if (myObject.Added != null && myObject.Added.Count > 0) 
            { 
                foreach (var temp in myObject.Added) 
                { 
                    orddata.Insert(0, temp); 
                } 
            } 
            if (myObject.Deleted != null && myObject.Deleted.Count > 0) 
            { 
                foreach (var temp in myObject.Deleted) 
                { 
                    orddata.Remove(orddata.Where(or => or.OrderID == temp.OrderID).FirstOrDefault()); 
                } 
            } 
 
            var data = orddata; 
            return Json(data); 
        } 
 
        public class submitvalue 
        { 
            public List<Order> Added { get; set; } 
            public List<Order> Changed { get; set; } 
            public List<Order> Deleted { get; set; } 
            public object Key { get; set; } 
        } 
 
 
        public class Order 
        { 
            public Order() 
            { 
 
            } 
            public Order(long OrderId, string CustomerId, int EmployeeId, double Freight, DateTime? OrderDate, string ShipCity) 
            { 
                this.OrderID = OrderId; 
                this.CustomerID = CustomerId; 
                this.EmployeeID = EmployeeId; 
                this.Freight = Freight; 
                this.OrderDate = OrderDate; 
                this.ShipCity = ShipCity; 
            } 
 
 
            public long? OrderID { get; set; } 
 
            public string CustomerID { get; set; } 
 
            public int? EmployeeID { get; set; } 
            public double? Freight { get; set; } 
            public DateTime? OrderDate { get; set; } 
            public string ShipCity { get; set; } 
        } 
    } 
} 
 
In client side 
 
    <ej-grid id="FlatGrid" allow-paging="true" allow-sorting="true" before-batch-save="beforeBatchSave" action-complete="complete" load="load"> 
        <e-datamanager url="Home/DataSource" batch-url="Home/BatchUpdate" adaptor="UrlAdaptor" /> 
        <e-edit-settings allow-adding="true" allow-editing="true" allow-deleting="true" edit-mode="@(EditMode.Batch)"></e-edit-settings> 
        <e-toolbar-settings show-toolbar="true" toolbar-items='@new List<string> {"add","edit","update","cancel"}' /> 
        <e-columns> 
        </e-columns> 
    </ej-grid> 
 
 
<script type="text/javascript"> 
 
             var customAdaptor = new ej.UrlAdaptor().extend({ 
                 processResponse: function (data, ds, query, xhr, request, changes) { 
                     window.flag = data.currentPage; // get page of 1st edited record from server side 
                     return ej.UrlAdaptor.prototype.processResponse(data, ds, query, xhr, request, changes); 
 
                 } 
             }) 
function beforeBatchSave(args) { 
        // set sorted column for sorting after edit 
           this.option({sortSettings: {sortedColumns: [{field:"ShipCity", direction:"ascending"}] }}) 
 } 
   
    function load(args) { 
        this.model.dataSource.adaptor = new customAdaptor(); 
    } 
    function complete(args) { 
        if (args.requestType == "batchsave") { 
            if (window.flag) { 
                var activeItem = $(".e-pager .e-active"); 
                var oldPage = activeItem.eq(0).text(); 
 
              // get pager element and change the selected value by changing class name 
                $(".e-numericitem").eq(oldPage - 1).removeClass("e-active e-currentitem"); 
                $(".e-numericitem").eq(oldPage - 1).addClass("e-default"); 
                $(".e-numericitem").eq(window.flag - 1).addClass("e-active e-currentitem"); 
                $(".e-numericitem").eq(window.flag - 1).removeClass("e-default"); 
                var obj = $(".e-grid").data("ejGrid"); 
 
              // set current page of page setting in grid instance 
                obj.model.pageSettings.currentPage = window.flag; 
                window.flag = false; 
            } 
        } 
    } 
</script> 


If you have further queries, please get back to us. 

Regards, 
Padmavathy Kamalanathan 


Padmavathy Kamalanathan [Syncfusion]
Replied On September 6, 2019 03:12 AM UTC

Hi Chris, 
 
Greetings from Syncfusion! 
 
QUERY:  the navigation on the left hand side of the Syncfusion Javascript API page isn't working.  It just shows the spinner. 
 
Please answer below question so that we can validate your query, 
 
1. Are you unable to access the navigation menu  while spinner display in the application?  
2. Have you set target as navigation menu right pane ? 
 
Regards, 
Padmavathy Kamalanathan 


Chris
Replied On September 6, 2019 02:28 PM UTC

Hi Chris, 
 
Greetings from Syncfusion! 
 
QUERY:  the navigation on the left hand side of the Syncfusion Javascript API page isn't working.  It just shows the spinner. 
 
Please answer below question so that we can validate your query, 
 
1. Are you unable to access the navigation menu  while spinner display in the application?  
2. Have you set target as navigation menu right pane ? 
 
Regards, 
Padmavathy Kamalanathan 


Hi,

The Syncfusion Javascript API help page is working again.

I have not had a chance to try out the latest code to update the paging.  Hopefully, I'll have time today or early next week.

Thanks,
Chris

Padmavathy Kamalanathan [Syncfusion]
Replied On September 9, 2019 08:57 AM UTC

Hi Chris, 

Thanks for your update. We are waiting to hear from you. 

If you have further queries, please get back to us. 

Regards, 
Padmavathy Kamalanathan 


Chris
Replied On September 9, 2019 09:57 PM UTC

Hi,

Getting closer, but the javascript for "batchsave" is not fully working.

What works:
1) If the "new page" number is within the range of numbers displayed in the pager at the bottom of the grid the currently selected page gets updated correctly.
For example: If I am on page 1 and after adding a new row the new page number should be 6 the currently selected page updates correctly.  (6 is highlighted)

What Doesn't Work
1) If the "new page" number is NOT within the range of numbers displayed in the pager at the bottom of the grid the currently selected page does NOT get updated correctly.
For example: If I start out on page 1 and after added a new row the new page numbers should be 37 the currently selected page does NOT update correctly.  It still displays the numbers between 1 and 8.  We need to somehow update the list of numbers so 37 is included in the range and that 37 is the currently selected page.
2) The next and previous buttons do not work correctly.
For example: If I start out on page 1 and after adding the currently selected page should be 7.  If I press next, it goes to page 2.  (not page 8)
3) Can we update the text on the right hand side?  For example, instead of saying "1 of 38 pages" it should say the currently selected page of 38 pages.  (for example, 7 of 38 pages).

Since I am using a session variable to determine what the currently selected page should be I have copied and pasted my "batchsave" code. 

        if (args.requestType == "batchsave") {

            var thisObj = this;
            var curPage = args.model.pageSettings.currentPage;
            var gridPageSettings = args.model.pageSettings;

            $.ajax({
                type: "POST",
                url: "/Common/GetIntegerSessionVariable",
                data: {
                    "variableName": "NewPageNum",
                    "zeroIfNull": true
                },
                success: function (pageNum) {
                    if (pageNum > 0) {
                        if (pageNum != curPage) {
                            //thisObj.gotoPage(pageNum);

                            $(".e-numericitem").eq(curPage - 1).removeClass("e-active e-currentitem");
                            $(".e-numericitem").eq(curPage - 1).addClass("e-default");
                            $(".e-numericitem").eq(pageNum - 1).addClass("e-active e-currentitem");
                            $(".e-numericitem").eq(pageNum - 1).removeClass("e-default");

                            //var objGrid = $("#mygridname").ejGrid("instance");
                            //var objGrid = $("#mygridname").data("ejGrid");
                            var objGrid = $(".e-grid").data("ejGrid");
                            objGrid.model.pageSettings.currentPage = pageNum;
                            //args.model.pageSettings.currentPage = pageNum;
                            //gridPageSettings.currentPage = pageNum;
                        }
                    }
                },
                error: function (data1) {
                    // do nothing
                }
            });
        }

Padmavathy Kamalanathan [Syncfusion]
Replied On September 10, 2019 12:12 PM UTC

Hi Chris, 
 
Thanks for your update. 
 
QUERY: If the "new page" number is NOT within the range of numbers displayed in the pager at the bottom of the grid the currently selected page does NOT get updated correctly. 
 
 
 
We are able to reproduce the reported issue at our end. The issue is due to the fact the pager element will not contain all the pages in it. The number of pages visible on pager element is based on the pageCount of grid. 
 
Please refer the below help documentation, 
 
 We suggest you to click the above mentioned element in image (which will show the next set of page numbers) in pager element programmatically, until it contains the specific page you need to navigate. Then you need to change the class name of the previous current page and set those classes to the page you need to set as current page. 
 
Even if we click that page element programmatically, it will hit the server. In order to avoid this, we suggest you to set args.cancel to true in the actionBegin event when the args.requestType is paging and flag is true (this flag is used because, the paging should not be cancel forever. 
 
Explanation of code with example, 
 
1)      If my grid has 8 pages, and the pageCount is 2, my current page is 1 . 
2)      If I edit and save record, that record get sorted and move to page 8 
3)      Now the pager element will not have page number 8. 
4)      So I need to click the above mentioned space 3 times( circled part in above image)  
5)      I need to programmatically get that element and click it thrice and for each click I need to prevent it hitting server side ( this is done in actionBegin event with requestType as “paging”. 
6)      The number of times we need to click that element is calculated from the “value” (value is 3 as per example) variable in code using current page and pageCount. 
7)      After making the pager element to contain our desired page, we need to remove class of old active page and add it to new page 
 
 
 
 
<script type="text/javascript"> 
 
    function complete(args) { 
        if (args.requestType == "batchsave") { 
            if (window.flag) { 
                var obj = $(".e-grid").data("ejGrid"); 
                var pageCount = obj.model.pageSettings.pageCount; 
                    var activeItem = $(".e-pager .e-active"); 
                var oldPage = activeItem.eq(0).text(); 
                //check if the page to be changed is greater than page count 
                if (window.flag > pageCount) { 
                    //check if previous current page is greater than pageCount 
           ( i.e the record you have edited is in page number greater than page count) 
                    if (oldPage > pageCount) { 
                        var value = (window.flag / pageCount) - (oldPage / pagecount); 
                    } 
                    else { 
                        var value = (window.flag / pageCount) - 1; 
                    } 
 
                    for (var i = 0; i < value; i++) { 
                        //window flag used to set args.cancel to true in action-begin 
                        window.flag1 = true; 
                        $(".e-NP").click(); 
                    } 
 
                    $(".e-numericitem").eq(1).removeClass("e-active e-currentitem"); 
                    $(".e-numericitem").eq(1).addClass("e-default"); 
                    var actualPager = (window.flag % pageCount); 
                    if (actualPager > 0) { 
                        $(".e-numericitem").eq(actualPager - 1).addClass("e-active e-currentitem"); 
                        $(".e-numericitem").eq(actualPager - 1).removeClass("e-default"); 
                    } 
                    else { 
                        $(".e-numericitem").eq(pageCount).addClass("e-active e-currentitem"); 
                        $(".e-numericitem").eq(pageCount).removeClass("e-default"); 
                    } 
                    obj.model.pageSettings.currentPage = window.flag; 
                     //  actionBegin event 
                    $(".e-pagermsg").prop({ textContent: " 8 of 8 pages (95 items)" }) 
                    window.flag = false; 
                } 
                else { 
                  //  use old code 
                } 
            } 
        } 
    } 
    function begin(args) { //  actionBegin event 
        if (args.requestType == "paging" && window.flag1) { 
            debugger; 
            args.cancel = true; //  cancelling server side action 
            window.flag1 = false; 
        } 
    } 
</script> 
 
 
QUERY2: The next and previous buttons do not work correctly. 
 
Try the above solution and let us know if  you still face this issue. 
 
QUERY3: Can we update the text on the right hand side? 
 
You can change the text on right side of pager as per your requirement using below code, in actionComplete event when requestType is batchsave 
 
 
$(".e-pagermsg").prop({ textContent: " 8 of 8 pages (95 items)" }) 
 
 
 
If you have further queries, please get back to us. 
 
Regards, 
Padmavathy Kamalanathan 


Chris
Replied On September 10, 2019 09:21 PM UTC



Thanks for all your help.  I finally got it working.  My code is a bit different then what you suggested; but it got me going in the right direction.

I used the same trick that you did to select the current page instead of using addClass and removeClass.  That way the Next and Previous page buttons work and it updates the pager message on the right hand side.

I can also go backward.  For example, if I am on page 39 when adding a new row it will go back to page 7 if it has to.  The only thing I am concerned about is if the following line of code will work in all situation: 

// sometimes we may want to go backwards...
var value = Math.abs(Math.floor((pageNum / pageCount) - (curPage / pageCount)));

It worked with the samples I tested.


Here is the rest of it:

        if (args.requestType == "batchsave") {           
            var curPage = args.model.pageSettings.currentPage;           

            $.ajax({
                type: "POST",
                url: "/Common/GetIntegerSessionVariable",
                data: {
                    "variableName": "NewPageNum",
                    "zeroIfNull": true
                },
                success: function (pageNum) {
                    if (pageNum > 0) {
                        if (pageNum != curPage) {
                           
                            var objGrid = $(".e-grid").data("ejGrid");
                            var pageCount = objGrid.model.pageSettings.pageCount;                            

                            if (pageNum > pageCount) {
                                if (curPage > pageCount) {
                                    var value = (pageNum / pageCount) - (curPage / pageCount);
                                } else {
                                    var value = (pageNum / pageCount) - 1;
                                }

                                for (var i = 0; i < value; i++) {
                                    window.isManualPaging = true;
                                    $(".e-NP").click();
                                }
                            } else {
                                // sometimes we may want to go backwards...
                                var value = Math.abs(Math.floor((pageNum / pageCount) - (curPage / pageCount)));
                               
                                if (value >= 1) {
                                    for (var i = 0; i < value; i++) {
                                        window.isManualPaging = true;                                       
                                        $(".e-PP").click();
                                    }
                                }
                            }

                            for (var numIdx = 0; numIdx < 15; numIdx++) {
                                var objNumItem = $(".e-numericitem").eq(numIdx);
                                if (objNumItem.length > 0) {
                                    var pagerPageNum = objNumItem[0].innerHTML;
                                    if (!isNaN(pagerPageNum)) {
                                        pagerPageNum = parseInt(pagerPageNum);

                                        if (pagerPageNum == pageNum) {
                                            window.isManualPaging = true;
                                            $(".e-numericitem").eq(numIdx).click();
                                        }

                                    }
                                   
                                }
                            }

                            objGrid.model.pageSettings.currentPage = pageNum;

                        }
                    }
                },
                error: function (data1) {
                    // do nothing
                }
            });
        }

Chris

Padmavathy Kamalanathan [Syncfusion]
Replied On September 11, 2019 11:45 AM UTC

Hi Chris, 

Thanks for your update. 

We are happy to hear that your issue has been resolved. 

The code you have shared is fine. 

If you need further assistance, please get back to us. 

Regards, 
Padmavathy Kamalanathan 

  


CONFIRMATION

This post will be permanently deleted. Are you sure you want to continue?

Sorry, An error occured while processing your request. Please try again later.

Please sign in to access our forum

This page will automatically be redirected to the sign-in page in 10 seconds.

Warning Icon You are using an outdated version of Internet Explorer that may not display all features of this and other websites. Upgrade to Internet Explorer 8 or newer for a better experience.Close Icon

Live Chat Icon For mobile
Live Chat Icon