This is a migrated thread and some comments may be shown as answers.

Trying to use RadClientDataSource to call an API method

9 Answers 307 Views
ClientDataSource
This is a migrated thread and some comments may be shown as answers.
Neil
Top achievements
Rank 1
Neil asked on 20 Dec 2019, 01:53 PM

I’m trying to set up a call to an api method inside of some client side javascript.
The javascript function (GetDb) is called from the ClientEvents-OnValueChanged event of a RadMaskedTextBox

In that javascript function I set the url of a RadClientDataSource and do a fetch. To be honest I don’t completely understand how this works and how I can access the data using the RadClientDataSource after the fetch. My goal is to call the api through the javascript and get data back that I need to use.

As you can see in the RadClientDataSource, I have a dummy url which I replace in the Javascript function GetDb. I did this because if there was an empty url in the RadClientDataSource I was unable to set the dataSource._transport.read.url in the javascript. The url will have to be created dynamically in the long run (right now it’s hard coded) so I am changing the transport url in the javascript. Eventually the final parameter in the rest call in the url will have to be passed and will be variable.

From what I can see the a RadClientDataSource is not being activated and the api method is not being called. After the fetch I looked at the data source property and there were no rows

I set up the API by creating a Controllers folder in my project and then adding a scaffolded controller that uses Entity framework. This API controller inherits from APIController.

I tested the controller by running the function I want to use (GetMeasureByControlName) in fiddler and it worked.

Below is the code. I pieced this together from existing examples but there is none that do exactly what I want. I’d appreciate any help.

<telerik:RadMaskedTextBox ID="RadMaskedTextBox1" runat="server" Width="80px" Mask="##.##" ClientEvents-OnValueChanged="GetDb" >  </telerik:RadMaskedTextBox>



<telerik:RadClientDataSource runat="server" ID="RadClientDataSource1">
    <DataSource>
        <WebServiceDataSourceSettings ServiceType="OData">
            <Select Url="localhost:53558/api/measure/GetProductById/blah" DataType="JSONP" />
        </WebServiceDataSourceSettings>
    </DataSource>
</telerik:RadClientDataSource>

I set a dummy url because unless there was something in there I couldn’t reset the transport url below in GetDb (javascript function).

 

Here is Clientside code called by the RadMaskedTextBox1 above:

function GetDb(sender, args) {
            debugger;
            var docTypeID='<%=Session["DocTypeId"]%>';
            if (args != null) {
                var value = args.get_newValue();
                var dataSource = $find("<%= RadClientDataSource1.ClientID%>");
                dataSource._transport.baseUrl = 'http://localhost:53558/api/documentmeasuretypes/';
                dataSource._transport.read.url = dataSource._transport.baseUrl + "GetMeasureByControlName/CYLINDER%20BLOCK%20HEIGHT";
                dataSource.fetch();
                var items = dataSource.view();
                var item = items[0];
                alert(item);
                alert('after fetch');
            }
        }

After the fetch the Total rows in the data source was 0.

The controller method does work; I tested it in fiddler. Here it is.
        public DocumentMeasureType GetMeasureByControlName(string controlname)
        {
            using (APIManufacturingEntitiesConsolidated db = new APIManufacturingEntitiesConsolidated())
            {
                var product = db.DocumentMeasureTypes.FirstOrDefault(m => m.MeasureName.Contains(controlname));
                if (product == null)
                {
                    throw new HttpResponseException(HttpStatusCode.NotFound);
                }
                return product;
            }
        }

 

And here is the routing:
  RouteTable.Routes.MapHttpRoute(
           name: "ActionApi",
           routeTemplate: "api/{controller}/{action}/{controlname}",
           defaults: new { id = RouteParameter.Optional }
);

            RouteTable.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = System.Web.Http.RouteParameter.Optional }




9 Answers, 1 is accepted

Sort by
0
Eric R | Senior Technical Support Engineer
Telerik team
answered on 23 Dec 2019, 03:51 PM

Hi Neil,

Thank you for providing the code snippet. I recommend using the Client-Side API that is included with the RadDataSource which will provide much of the functionality that you are looking for. Although, I think this can be better understood by reviewing an example. See the How To Use ClientDataSource with WebAPI documentation and the code sample provided in the Client-Side DataBinding with WebAPI Code Library

Please give this a try and let me know if you have any additional questions. Thank you and I look forward to your reply.

Regards,


Eric R | Technical Support Engineer
Progress Telerik

Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
0
Neil
Top achievements
Rank 1
answered on 26 Dec 2019, 01:54 PM

Eric,

  Thanks so much for your quick reply. The reason I sent my obviously flawed code snippets is because I was intrigued by the idea that you could use a RadClientDataSource and access Data through an api. I really appreciate your downloadable example. But, as in my flawed example I don't want to have to embed the RadClientDataSource in another control to make it execute and return data.

We have some very old fashioned api calls in the code behind that I inherited that I found weren't thread safe (I called the same one twice in a row and the system locked up). I had hoped that the RadClientDataSource with apicontroller would solve this problem.

The example you gave me was perfect except for one thing. I would like to be able to use the RadClientDataSource and apicontroller separately from any other control. Like many of the examples you have the one you sent is embedded in a radgrid. While it showed me a lot of what I need to know, I would like to simply create a RadClientDataSource an api controller, set off the call to the controller, get the data back and consume it. That is why there is no other controls in my code snippets. I am using a RadMaskedTextBox and I need to validate data entered into it in javascript. Since I want to use and apicontroller to get the data to validate was was entered into RadMaskedTextBox I'm hoping to find a way to create a RadClientDataSource with an API controller and simply "call" the apicontroller through the RadClientDataSource without it being attached to any other control. Since the radgrid calls the the RadClientDataSource "under the hood" I have no direct way to set off the RadClientDataSource and have it call the api controller.

In case there's a better way to do this I'll outline exactly what I want to do:

1. Have a user enter a number in a field in a RadMaskedTextBox 

2. Have the RadMaskedTextBox call some client side java script through a declaration of the javascript  function in  

the RadMaskedTextBox; I am currently trying to tie the javascript function to the ClientEvents-OnValueChanged clause in the RadMaskedTextBox.

3. Have the javascript function "call" or activate the RadClientDataSource and have it return data through the apicontroller into the RadClientDataSource.

4. The javascript function would be able to access the data returned from the RadClientDataSource as shown in your examples. 

5. The data would  then be compared to what is entered into the field in the RadMaskedTextBox, basically see if the entered number falls into range defined in the data returned from RadClientDataSource. 

Of course I hope that this call, if done repeatedly would be thread safe. I want to replace all the old fashioned api calls with this new technique.

Can you point me in the right direction?

Thanks,

Neil

0
Eric R | Senior Technical Support Engineer
Telerik team
answered on 26 Dec 2019, 05:46 PM

Hi Neil,

Thank you for a thorough explanation of the scenario. Although, I am not sure that using the RadMaskedTextBox in this way is the best approach. For example, the OnValueChanged method is raised once the textbox control loses focus. A better approach might be to use OnKeyPress. In this case, you would be able to validate the value of the text after each keypress. Alternatively, the controls include specific validation built-in. I recommend reviewing the TextBox - Validation demo for more details.

As for the RadClientDataSource, this is a wrapper around the Kendo UI DataSource and has specific methods for doing CRUD operations. I recommend reviewing the various Client-side API methods. These methods make it possible to use with any control event on the Client-side. For example, the Fetch operation might be used to get all data from the DataSource.

For additional reference, I have attached a sample that queries a specific route on the WebAPI using the PageLoad Client-side event and KeyPress event of the MaskedTextBox.

I hope this helps. Please let me know if you need any additional information. Thank you.

Regards,


Eric R | Technical Support Engineer
Progress Telerik

Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
0
Neil
Top achievements
Rank 1
answered on 26 Dec 2019, 08:16 PM

First of all, unfortunately unlike your last example, the latest project you sent me runs on a later version of VS than I have. I can get my boss to give me credentials for 2019 but, as you know, that can take some phone time with MS. I see a views folder so I am thinking it is MVC.

However I did take this function from the code.

        function getAllDataSourceData() {
                    var dataSource = $find('MainContent_RadClientDataSource1');
                    debugger
                    dataSource.fetch(function (args) {
                        var data = args.get_data();
                        alert(data.length);
                        alert(data[data.length - 1]);
                    });

                  alert(dataSource);

As you can see i added an alert which didn't really tell me anything though it did appear as an object. The fact of the matter is:

1. I ran this from onkey press in the RadMaskedTestbox as you suggested.I changed the console logs to alerts. No alerts within the anonymous function appeared. Do alerts not work in anonymous functions? I know the main function ran because I put a debugger statement in it. And the alert showing the datasource does show that it's a valid object.

2. I ran the same function from page load. Again it stopped after the debugger statement so I know it ran. However the two alerts didn't work in that case either. I can't tell why. It looks like the anonymous function is not running.

I didn't mention it last time because the first project you sent me seemed to be for webforms. It has an aspx page. The second project seemed to be mvc since I saw a views folder

Just to let you know I am working with webforms at the moment. And using VS2015. Is the fact I'm using webforms causing the anonymous function not to work?

You'll also notice that the "Fetch" mentioned in the overview page you listed in your last function is what I used in my code snippet at the very top of this thread. That snippet of javascript is what I would like to use, at least in theory.

Is there a more direct way to use the RadClientDataSource1 without linking it to other controls. Or should I forget about that since it won't work. Is this an issue of trying to do this with the Ajax UI controls and not kendo (which I know nothing about)? What can I try next? Do I need to leave those console.logs in the function and not use alerts (meaning that I would have to run the javascript in the javascript debugger I would assume).

Any help would be appreciated. If I need to go a more ordinary route, perhaps using a dataadapter and some sql strings please let me know. While I would like to use an api I figure if there is no simple solution to this I will have to go that route.

Thanks,

Neil

0
Eric R | Senior Technical Support Engineer
Telerik team
answered on 26 Dec 2019, 09:15 PM

Hi Neil,

Thank you again for your thorough response. The previously provided sample project is an ASP.NET WebForms project and the most relevant information was in the Default.aspx page under the Views Folder. For reference, I have also provided all the relevant code in the snippet below. 

<telerik:RadCodeBlock runat="server" ID="RadCodeBlock1">
    <script type="text/javascript">
        function pageLoad() {
            getAllDataSourceData();
        }

        function fetchData() {
            getAllDataSourceData();
        }

        function getAllDataSourceData() {
            var dataSource = $find('<%= RadClientDataSource1.ClientID %>');
            //debugger
            dataSource.fetch(function (args) {
                var data = args.get_data();
                //debugger
                console.log(data.length);
                console.log(data[data.length - 1]);
            });
        }
    </script>
</telerik:RadCodeBlock>
<div>
    <telerik:RadMaskedTextBox ID="RadTextMaskedBox1" runat="server" Mask="##.##">
        <ClientEvents OnKeyPress="fetchData" />
    </telerik:RadMaskedTextBox>
    <telerik:RadClientDataSource ID="RadClientDataSource1" runat="server">
        <DataSource>
            <WebServiceDataSourceSettings ServiceType="Default">
                <Select Url="/api/pricing" />
            </WebServiceDataSourceSettings>
        </DataSource>
    </telerik:RadClientDataSource>
</div>

Essentially, this is calling the Declared Select Method on the RadClientDataSource in the fetch callback method. Additionally, I recommend ensuring that there aren't any Client-Side events on the RadClientDataSource. If one is defined it will take precedence over the callback. 

As for debugging, I do recommend using the console.log or debugger approach when reading JSON data. It is easier to interpret this way. We also have a great write up by my colleague about Debugging in the Browser DevTools.

For the sample, I have updated it to meet your expectations. I removed the Views Folder and moved the Default.aspx page to the top-level. In order to run the sample in Visual Studio 2015, double-click the .csproj file as shown in the below screenshot and ensure the Telerik NuGet Feed is configured in Visual Studio. This will restore the NuGet packages on build.

Generally, if I start to think it is getting too complicated, then it most likely is and I have wandered too far out into the weeds. If you feel that the alternative approach with a SqlDataAdapter is more appropriate, I would recommend going that route.

Please let me know if you have any additional questions. Thank you.

Regards,


Eric R | Technical Support Engineer
Progress Telerik

Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
0
Neil
Top achievements
Rank 1
answered on 27 Dec 2019, 04:22 PM

Thanks for all your help. I just tried to make the nuget packages come down for telerik but immediately saw a confusing error message before I could do it. Obviously, as you suggested,  this may be require more fixing than is worth the time. I looked at sever side events for the MaskedTextBox and found the text change event. I can use that with a dataadapter or maybe I can figure out a way to use the api from there. 

I will point out that being new to telerik, it is often hard to find information but you have been very helpful. Everything seems to hinge on that anonymous function which does not cause an error but I can't see any evidence that it's doing anything. So I'll ask two more questions:

1. That example you gave me seems to not show how to actually read fields though I figure this line. may do that though I'm not sure if it's reading an array of fields:

alert(data[data.length - 1]

Is that reading data?

2. I now have the RadMaskedTextBox in an editItemTemplate. This line will no longer find the control:

var grid = $find("<%= RadGridByMeasure.ClientID %>");

I have looked up ways of finding controls buried in templates in javascript but nothing I've tried have worked. Can you make a suggestion?

I'll show the error just in case it might mean anything to you. The code seems to be working in my project so I can continue to work with that when I have time. I will point out that you suggested I use the "debugger" technique to see what is happening with the anonymous function. I have been using the debugger technique and it seems like the anonymous function, while causing no errors, is doing nothing as I found when I replaced the console.logs with alerts. Is there a way I can make sure it's working?

 

Here is the error. I will switch to the server side solution (which I hope will work :-) ) for the moment but would like to get more familiar with the javascript side of telerik. I found i could simple put data access javascript in my functions but they are considered insecure so that option is out.

Thanks again. Here's the error.

 

SeverityCodeDescriptionProjectFileLineSuppression State
ErrorThe reference assemblies for framework ".NETFramework,Version=v4.7.1" were not found. To resolve this, install the SDK or Targeting Pack for this framework version or retarget your application to a version of the framework for which you have the SDK or Targeting Pack installed. Note that assemblies will be resolved from the Global Assembly Cache (GAC) and will be used in place of reference assemblies. Therefore your assembly may not be correctly targeted for the framework you intend.TWA.MaskedTextBoxRadClientDataSource

0
Eric R | Senior Technical Support Engineer
Telerik team
answered on 27 Dec 2019, 05:26 PM

Hi Neil,

The Array["Index"] notation is for accessing an item in a JavaScript array. Essentially, the data[data.length-1] returns the last item. Additionally, it would return the whole object/value instead of just the index. For example, if it were a person object with FirstName and LastName properties it would include those properties in JSON form. 

I am not sure about the editItemTemplate control as this isn't one of our controls. Additionally, I don't think the $find("CONTROL_ID") method will query for nested controls and if the control isn't rendered/available at the time the method is called it will throw an error.

I recommend reviewing the following articles/resources for getting started with JavaScript in UI for ASP.NET AJAX. 

- Get Client-side Reference to a Control Object

- Using jQuery

- Improve your Debugging Skills with Chrome DevTools

- The Chrome DevTools Sources Panel

- The JavaScript Debugger Statement

As for the error, this appears to be because the .NET Framework 4.7.1 SDK isn't installed. This can be found at the Microsoft Downloads page.

Before I close, I would like to recommend that you signup for a subscription and take advantage of our On-Demand Training. We offer many courses that will get you started with our products. More details are available at our purchase page

In the meantime, please let me know if you have any additional questions regarding our tooling. Thank you for using the UI for ASP.NET AJAX Forums.

Regards,


Eric R | Technical Support Engineer
Progress Telerik

Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
0
Neil
Top achievements
Rank 1
answered on 27 Dec 2019, 07:31 PM

Just to clarify, EditItemTemplate is a formatting device; it is used, as far as I know, only in the radgrid to create read only vs edit controls for those functions within the radgrid. I can't imagine it's impossible that you can't access radgrid child controls in javascript, especially since there is ajax under the hood of all these controls. I am more than curious how to find objects within these templates as I'm sure I'll run into this again. 

I believe the issue with the anonymous function not showing any output is something that we could investigate but it seems like that isn't possible. I'll be honest and say that I've worked with other control sets and I find that this one has a number of details that are not obvious from the documentation. 

Anyway, thank you for your help. I'll address this when I have time. I will assume that the training you mention is not free and therefore won't be available to me. 

0
Eric R | Senior Technical Support Engineer
Telerik team
answered on 27 Dec 2019, 09:00 PM

Hi Neil,

That makes more sense. My apologies for not fully understanding that initially. The RadMaskedTexbox is in an EditItemTemplate of a Template Column for a RadGrid. You are correct it is possible to access the Grid Rows on the Client-side. Additionally, to get the control use the $telerik.findControl client-side method. See the below code snippet for an example.

 

var EntityKeyName = $find("<%= RadGrid_ECNEntity.ClientID%>").get_masterTableView().get_dataItems()[0].findControl("RadComboBox_EntityKeyName");

 

Additionally, I recommend reviewing the Client-Side Programming section for each control that you are working with to get an understanding of the available properties and events.

Unfortunately, the training is available to customers with a subscription. An alternative resource might be to ask a question on StackOverflow as well.

I hope this information helps. Please let me know if you have any additional questions. Thank you.

Regards,


Eric R | Technical Support Engineer
Progress Telerik

Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
Tags
ClientDataSource
Asked by
Neil
Top achievements
Rank 1
Answers by
Eric R | Senior Technical Support Engineer
Telerik team
Neil
Top achievements
Rank 1
Share this question
or