JSON data fetched using API not being displayed using JQuery and Handlebars - javascript

So, I am creating this webapp that utilizes the BetterDoctor's API to fetch a list of doctors related to a particular practice (like cardiology).
I am using Handlebars, JQuery, HTML, and JS to do this.
A screenshot of what the code looks like in the browser
When I try and run the code on the browser, the data can't be seen in the template as defined in the HTML page under the {{#data}} tag. Whilst inspecting the page and taking a look at the browser console, I couldn't find anything wrong since the console.log was returning the correct url that had the required JSON data from which data was meant to be fetched from.
Any help regarding this issue would be of great help and very much appreciated.
Here's a pen containing the code:https://codepen.io/sandeeprao/pen/OzbQJY?editors=1010
You can see the error
Here's my HTML
<div>
name a speciality: <input type="text" id="speciality">
<br></br>
enter state (in short form): <input type="text" id="state">
<br></br>
lattitude: <input type="text" id="lat" value="">
longitude: <input type="text" id="lon" value="">
</div>
<div id="content-placeholder"></div>
<script id="docs-template" type="text/x-handlebars-template">
<table>
<thead>
<th>Name</th>
<th>Title</th>
<th>Bio</th>
</thead>
<tbody>
{{#data}}
<tr>
<td><p>{{profile.first_name}} {{profile.last_name}}</p><br>
<td>{{profile.title}}</td>
<td>{{profile.bio}}</td>
</tr>
{{/data}}
</tbody>
</table>
</script>
Here is the JS file for it:
var base_url = 'https://api.betterdoctor.com/2016-03-01/practices?';
function go2(){
var speciality = document.getElementById('speciality').value;
var state = document.getElementById('state').value;
var url_search = {
name: speciality,
location: state,
user_location: '',
skip: 0,
limit: 10,
user_key: 'CODE_SAMPLES_KEY_9d3608187'
}
console.log(speciality);
console.log(state);
var url = base_url + jQuery.param( url_search );
console.log(url)
$.get(url, function (data) {
// data: { meta: {<metadata>}, data: {<array[Practice]>} }
var template = Handlebars.compile(document.getElementById('docs-
template').innerHTML);
document.getElementById('content-placeholder').innerHTML = template(data);
});
}

The issue has been sorted out. I figured out that there was a problem in the handlebars code and interpreting the JSON format of the API's result.
<td>{{#doctors}}
{{profile.first_name}}{{profile.last_name}}{{/doctors}}</td>
<td>{{doctors.profile.first_name}} {{doctors.profile.last_name}}</td>
That's the fix!

Related

My angular can't get the value from html page

I have an angular function to call me rest service but it can't get the value from the html file. when i press submit the $scope.productForm is, although i still have value in my html page.
Main.js
$scope.products = [];
$scope.productForm = {
ID:1,
Name:"",
Description:"",
URL:""
};
_refreshProductData();
//Add or Update Product
$scope.submitProduct = function() {  
var method = "";
 
if ($scope.productForm.ID == -1) {
    method = "POST";
} else {
    method = "PUT";
}
 
$http({
    method: method,
    url: '/product',
    data: angular.toJson($scope.productForm),
    headers: {
        'Content-Type': 'application/json'
    }
}).then(_success, _error);
}
index.html
<form ng-submit="submitProduct()">
    <table border="0">
        <tr>
            <td>ProductID</td>
            <td>{{productForm.ID}}</td>
        </tr>
        <tr>
            <td>Product Name</td>
            <td><input type="text" ng-model="productForm.Name" /></td>
        </tr>
        <tr>
            <td>Product Description</td>
            <td><input type="text" ng-model="productForm.Description"  /></td>
        </tr>
<tr>
            <td>Product URL</td>
            <td><input type="text" ng-model="productForm.URL"  /></td>
        </tr>
        <tr>
            <td colspan="2">
                <input type="submit" value="Submit" class="blue-button" />
            </td>
        </tr>
   </table>
</form>
data: angular.toJson($scope.productForm) can have value from index.html
Like others have said, you have a number of things you need to address.
main.js doesn't have a function _refreshProductData defined. I'm assuming this is breaking your script and why $scope.submitProduct() isn't executing.
When defining your _refreshProductData function, you need to attach it to the controller's $scope(i.e. $scope._refreshProductData = function(){//refresh data} if you want it to be accessible to the html template. Otherwise, you wouldn't need to attach $scope to it. You would need to update your call to this function based on the approach you take.
$scope._refreshProductData();--> you should call your function this way.
_refreshProductData();-->_refreshProductData is not defined(F12)
I have assumed that the function was created in my previous answer.
1)create your function in main.js
$scope._refreshProductData() = function()
{
write codes here...
}
then call the function in place
2) $scope._refreshProductData();

POST not supported exception after call to REST service using XHR send

I have a REST api developed using Spring Boot which accepts POST requests and does some processing on them. It would then redirect to a different results page.
The controller is as follows:
#RequestMapping(method = RequestMethod.POST, value = "/person")
public String arrayTest(#RequestParam("personid") String personid, Model model) throws IOException{
CoreDriver driver=new CoreDriver();
ResultData result=driver.initProcess(personid);
model.addAttribute("attr",result.getMismatchList());
return "results";
}
In this case, after the initProcess function is complete, it would be redirected to a page: results.html
This works when i invoke the service using a form submit as follows:
<form id="mainform" method="POST" enctype="multipart/form-data" action="/person">
<table BORDER="1">
<tr>
<td>Enter person ID</td>
<td>
<input type="text" name="personid" id="person">
</td>
</tr>
<tr>
<td><input type="submit" value="submit"/></td>
</tr>
</table>
</form>
However, when I invoke the service using the send function of XHR, it successfully invokes the REST api but it does not redirect to the results.html page. Instead it gives me an error: Request method 'POST' not supported.
My javascript for this is as follows:
upload: function(image_data_uri, target_url, callback) {
var http = new XMLHttpRequest();
http.open("POST", target_url, false);
var form = new FormData();
var arrayLength = proc_image_data.length;
for (var j = 0; j < arrayLength; j++) {
form.append( form_name, proc_data[j], form_name+"."+fmt.replace(/e/, '') );
}
http.send(form);
}
This JS function is called using the following form:
<form id="mainform" method="POST" enctype="multipart/form-data" action="">
<table BORDER="1">
<tr>
<td>Enter person ID</td>
<td>
<input type="text" name="personid" id="person">
</td>
</tr>
<tr>
<td><input type="submit" value="submit" onclick="shot()"/></td>
</tr>
</table>
</form>
function shot() {
var personId=document.getElementById('person').value;
var url='/person?personid='+personId;
Test.upload( webcamuri, url, function(code, text) {
} );
}
I'm not sure why the redirection works when i invoke the api directly from the form but not via the JS that uses XHR send. Could you please help in identifying the issue here?
This is a problem related to CORS - cross origin resource sharing. To be able to access the REST service via XHR, the service must send the right headers to the browser (which probably is doing a prefligth request).
You can achieve this in your REST controller by adding the #CrossOrigin annotation to your arrayTestmethod. (see Spring docu)
So I was able to resolve the issue after a bit of debugging. I removed the method attribute from the form as well as added the following code inside the callback function for Test.upload():
document.write(text);
So basically, text returns the html of the redirected page. So once the XHR send call is complete, the html is written to the browser via the callback.

How knockout know about data-binded object if it has only its name?

I have something like:
<form action='/someServerSideHandler'>
<p>You have asked for <span data-bind='text: gifts().length'> </span> gift(s)</p>
<table data-bind='visible: gifts().length > 0'>
<thead>
<tr>
<th>Gift name</th>
<th>Price</th>
<th />
</tr>
</thead>
<tbody data-bind='foreach: gifts'>
<tr>
<td><input class='required' data-bind='value: name, uniqueName: true' /></td>
<td><input class='required number' data-bind='value: price, uniqueName: true' /></td>
<td><a href='#' data-bind='click: $root.removeGift'>Delete</a></td>
</tr>
</tbody>
</table>
<button data-bind='click: addGift'>Add Gift</button>
<button data-bind='enable: gifts().length > 0' type='submit'>Submit</button>
</form>
and
var GiftModel = function(gifts) {
var self = this;
self.gifts = ko.observableArray(gifts);
self.addGift = function() {
self.gifts.push({
name: "",
price: ""
});
};
self.removeGift = function(gift) {
self.gifts.remove(gift);
};
self.save = function(form) {
alert("Could now transmit to server: " + ko.utils.stringifyJson(self.gifts));
// To actually transmit to server as a regular form post, write this: ko.utils.postJson($("form")[0], self.gifts);
};
};
var viewModel = new GiftModel([
{ name: "Tall Hat", price: "39.95"},
{ name: "Long Cloak", price: "120.00"}
]);
ko.applyBindings(viewModel);
// Activate jQuery Validation
$("form").validate({ submitHandler: viewModel.save });
how it is happening that ko.applyBindings(viewModel); is magically making biding by name of variable? Is knockout searching it somehow by name? How the template know that this is his array/data set? I am basically .net developer so in my mind taking something "by name" is not clear. Or maybe am I wrong that this is taken by name? I read documentation but I still do not get the way how knockout connect template gifts() with array named gifts from model?
but the way this is sample from knockout main page.
http://knockoutjs.com/examples/gridEditor.html
how it is happening that ko.applyBindings(viewModel); is magically making biding by name of variable? Is knockout searching it somehow by name?
Cutting some corners here, but two things in which Javascript (not so much KO) differs from .NET, as related to your question:
All members (e.g. self.gifts) can also be accessed as if self had a string based indexer to get them (e.g. self['gifts']);
Javascript is dynamically typed, so self['gifts'] can at run time contain an array, string, observable: whatever.
So, Knockout can take your string "gifts" use it to get to the variable self["gifts"] and at run time check for its type to see if it's an array, observable y/n, etc, and choose the appropriate code path accordingly.
As for your other question:
How the template know that this is his array/data set?
Knockout is open source (though perhaps not easy to read when starting out with JS), and if you dive in to it you'll find that foreach assumes it's passed an array.

How to process a json and return a new json

What I'm trying to make is an angular app that reads in a json file and displays them, and allows users to edit the json file using html controls. Then, the user can create a new json object based on their selections and display it.
Here is a picture to help describe what I'm trying to do:
So, the user sees this, they make certain selections, e.g. lock them or delete them, then they hit create, and a new json file is returned based on which objects they have chosen to lock or delete.
At the moment I just have a standard angular app which gets and displays the json:
var app = angular.module('myApp', []);
app.controller('customersCtrl', function($scope, $http) {
$http.get("http://www.w3schools.com/angular/customers.php").then(function (response) {
$scope.myData = response.data.records;
});
$scope.createJson = function(){
// Create new json file
};
});
The body of my html/my angular app looks like this at the moment:
<div ng-app="myApp" ng-controller="customersCtrl">
<table>
<tr ng-repeat="x in myData">
<td>{{ x.Name }}</td>
<td>{{ x.City }}</td>
<td>{{ x.Country }}</td>
<td><input type="checkbox" name="lock" value="{{x.Name}}"></td>
<td><input type="checkbox" name="delete" value="{{x.Name}}"></td>
</tr>
</table>
<button ng-click="createJson()">Create</button>
</div>
Baiscally, I'm not sure if my approach is correct at the moment, and if it is, I don't really know what my next step is.
P.S. this is just test data I am using for the sake of learning/testing, it is not my data, I got it from: http://www.w3schools.com/angular/customers.php
You can try
JSON.stringify($scope.myData)
or
angular.toJson($scope.myData)
this will give you string representation of your data object. The rest is up to you, you may assign it to textarea, post it back to server (in this case, you most likely won't even need to encode it before) etc.
You should use
<td><input type="checkbox" name="lock" value="{{x.Name}}"></td>
<td><input type="checkbox" name="delete" value="{{x.Name}}"></td>
as
<td><input type="checkbox" name="lock" ng-model="x.Name"></td>
<td><input type="checkbox" name="delete" ng-model="x.Name"></td>
(Actually I didn't understand why you use string in checkbox. It should be boolean value).
By this way any change will change your $scope.myData.
On create you should take info from user and create a new JsonObject like
var newObject = {
Name: 'Name Surname',
City: 'City',
Country: 'Country'
}
And add this to your myData with;
$scope.myData.push(newObject);
I ended up creating an appropriate solution by simply creating a new and empty JSON object:
var newJson = [];
and populating it by looping through my original one and using array.push() to add the selected entries:
for (var person in $scope.myData){
if($scope.myData[person].Delete === false || $scope.myData[person].Lock === true){
newJson.push($scope.myData[person])
}
}

AngularJs. Problems with ng-repeat

I'm having two tables witch renders data trough angularJs, coming from 2 c#-methods.
The tables are structured almost exactly the same. The first one below is used as I searchfield and the other one is used basiclly to render names.
My problem is that the first one works perfect, but the other one does not. And I don't see the problem. Any help would be appreciated. // Thanks!
Here are my two tables. (the first one is working)
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.18/angular.min.js"></script>
<div ng-app="searchApp">
<div ng-controller="searchController">
#*first table works*#
<span style="color: white">Search:</span> <input data-ng-click="myFunction()" ng-model="searchText">
<table style="color: white" id="searchTextResults">
<tr><th>Name</th></tr>
<tr ng-show="!!searchText.length != 0" ng-repeat="friend in friends | filter:searchText">
<td data-id="{{friend.id}}" data-ng-click="SendFriendRequest(friend.id)">{{friend.id.replace("RavenUsers/","")}}</td>
</tr>
</table>
#*Does not work*#
<input type="button" value="Get friends requests" data-ng-click="GetFriendRequests()">
<table style="color: white">
<tr><th>Friend requests</th></tr>
<tr ng-repeat="friendRequest in friendRequests">
<td data-id="{{friendRequest.UserWhoWantsToAddYou}}" data-ng-click="acceptUserRequest(friendRequest.UserWhoWantsToAddYou)">{{friendRequest.UserWhoWantsToAddYou}}</td>
</tr>
</table>
</div>
</div>
HERE IS MY SCRIPT
<script>
var App = angular.module('searchApp', []);
App.controller('searchController', function ($scope, $http) {
//Get all users to the seachFunction
$scope.myFunction = function () {
var result = $http.get("/Home/GetAllUsersExeptCurrentUser");
result.success(function (data) {
$scope.friends = data;
});
};
//Get friendRequests from other users
$scope.GetFriendRequests = function () {
var result = $http.get("/Home/GetFriendRequests");
result.success(function (data) {
$scope.friendRequests = data;
});
};
});
</script>
The first script-function called myFunction works perfect and the data coming from my c#-method looks like this:
[{"id":"RavenUsers/One"},{"id":"RavenUsers/Two"},{"id":"RavenUsers/Three"}]
The second script-function called GetFriendRequests does not work, and as far as I can see there is no difference between this data passed into here than the data passed into myFunction:
[{"userWhoWantsToAddYou":"RavenUsers/Ten"},{"userWhoWantsToAddYou":"RavenUsers/Eleven"}]
I'd suggest you use then instead of success because $http returns a promise.
If your table doesn't "render" then put a breakpoint inside success function, console.log() the data or check friendRequests inside your HTML template, e.g. using <div>{{ friendRequests | json }}</div>, to ensure you actually got data from response.
Now you do not handle exceptions at all.
Example:
result.then(function(data) {
console.log('got data')
},function(error) {
console.log('oh noes :( !');
});
Related plunker here http://plnkr.co/edit/KzY8A3
It would be helpful if you either (a) provided a plunker to your code or (b) provided the error message.
ng-repeat requires a uniquificator on each item in the repeat, which defaults to item.id. If you don't have an id field on the item, you'll need to tell angular what field to use.
https://docs.angularjs.org/api/ng/directive/ngRepeat
So I'd suggest changing
<tr ng-repeat="friendRequest in friendRequests">
to
<tr ng-repeat="friendRequest in friendRequests track by userWhoWantsToAddYou">
and see if that works.

Categories