Can someone please explain and show, how I can render a complex JSON object with Angular.
I am making a call to the FourSquare API which returns a list of recommended venues based on my search(location). The JSON file is huge and am finding it difficult to render out the relevant data in it.
Here is what my JSON looks like:
https://developer.foursquare.com/docs/explore#req=venues/explore%3Fnear%3DEarlsfield
Here is the function in my controller which makes a call to the url.
Note; baseurl = the url i built up with my AccessId and Secret
//Get response from server
function fetch(){
$http.get(baseurl + $scope.search)
.success(function(response){
console.log(response.response.groups[0].items);
$scope.details = response;
});
I would then like to be able to render out my results in an ul with lis. Each LI would have the name of the venue as well as other information. At the moment I have the following:
<div ng-if="!details">
Loading...
</div>
<div ng-if="details.Response==='True'">
<ul ng-repeat='groups in response'>
<li>{{item.name}}</li>
<li>{{item.address}}</li>
</ul>
</div>
<div ng-if="details.Response==='False'">
No results found.
</div>
CODEPEN LINK:
http://codepen.io/AntonioVassilev/full/EVrKxp/
I am a novice in Angular and am finding it confusing browsing through large data objects like this one. Help appreciated
The details is a Object and you can't loop on it. Fetch groups first: like details.groups
JSON structure: http://screencloud.net/v/Oqd
Some example:
<ul ng-repeat='group in details.groups'>
<li>{{group.name}}</li>
<li>{{group.type}}</li>
<ul ng-repeat='item in group.items'>
<pre>{{item}}</pre>
</ul>
Some demo you can play with
You should be repeating on your scope variable (scope.details). According to your js the correct ng-repeats seem to be sth like this:
<div ng-repeat='groups in details'>
<div ng-repeat='group in groups'>
<ul ng-repeat='item in group.items'>
<li>{{item.name}}</li>
<li>{{item.address}}</li>
</ul>
</div>
</div>
Related
Hey everyone, thank you very much for your help. Question is edited per suggestions in the comments.
I'm new to Mongo and Meteor.
I have a collection "posts" with a field "slug".
The "post" template is populating correctly with each post's values. Slug value is always something like "my-great-post".
I need to get the text value for the _id's slug, which will be different each time the template is accessed, encode it, write a string, and spit the string back out into the template.
Things tried
can't return a value for "this.slug" or "this.data.slug" in either template helpers or onRendered, even though collection is defined and correctly populating spacebars values in the template
"this" returns "[object Object]" to console.log
app crashes when I try to javascript encode and deliver a string from the helper, probably I don't fully understand helper syntax from the documentation
(I followed advice in the comments to avoid trying to create scripts in the template html, so below is more information requested by everyone helping on this thread)
- Template html -
{{#with post}}
<div class="blog-article">
<div class="blog-header">
<div class="left">
<!-- title -->
<h1 class="post-title">{{title}}</h1>
<div class="holder">
<div class="post-tags">
<!-- tags -->
{{#each tags}}
<span>{{this}}</span>
{{/each}}
</div>
</div>
</div>
</div>
<div class="blog-post">
<div class="blog-copy">
<!-- date -->
<div class="post-date">{{post_date}}</div>
<!-- social -->
<div class="blog-social">
<!--
<a class="so-facebook" target="_blank" href="need to encode slug here"></a>
-->
</div>
<!-- ============== post ============== -->
{{{content}}}
<!-- ============ end post ============ -->
</div>
</div>
</div>
{{/with}}
- Template js -
Template.post.onCreated(function() {
var self = this;
self.autorun(function() {
var postSlug = FlowRouter.getParam('postSlug');
self.subscribe('singlePost', postSlug);
});
});
Template.post.helpers({
post: function() {
var postSlug = FlowRouter.getParam('postSlug');
var post = Posts.findOne({slug: postSlug}) || {};
return post;
}
// can't get these working in a helper, out of helper they crash the app
// console.log(this.slug);
// console.log(this.data.slug);
});
Template.post.onRendered( function () {
// these do not work
// console.log(this.slug);
// console.log(this.data.slug);
});
db.posts.findOne();
{
"_id" : ObjectId("576c95708056bea3bc25a91f"),
"title" : "How Meteor Raised the Bar For New Rapid-Development Technologies",
"post_date" : "May 28, 2016",
"image" : "meteor-raised-the-bar.png",
"slug" : "how-meteor-raised-the-bar",
"bitlink" : "ufw-29Z9h7s",
"tags" : [
"Tools",
"Technologies"
],
"excerpt" : "sizzling excerpt",
"content" : "bunch of post content html"
}
If some one can solve this using any method, I will accept answer with joy and gratitude most intense.
The problem is probably with the parent template, rather than this one. The way that Meteor works is that the JS files are separated from the HTML, so don't try to include a <script> tag in the HTML.
The first thing is that you have to load all of your documents into the client. (NOTE: once you've got the hang of that, then you can worry about only loading the documents that you need).
To do that, you need a collection and a publication. By default all collections are automatically published completely, so unless you removed the autopublished module, then I'll assume that it is still loaded.
So let's start with the parent template. In this case, I'm going to just loop through all of the posts in the collection and display them using the innerTemplate.
<template name=parent>
<ul>
{{#each post}}
{{> innerTemplate}}
{{/each}}
</ul>
</template>
And now our inner template might look like this:
<template name=innerTemplate>
<li>{{slug}}</li>
</template>
The end result will be a simple list with each slug.
Now, to link everything together, we need to create a JS file, which will:
1. define the collection on both client and server
2. pass the collection to the parent template
This file should be accessible to both the client and the server.
posts = new Mongo.Collection('posts');
if(Meteor.isClient) {
Template.parent.helpers({
posts() {
return Posts.find();
}
});
}
Now, if you want to do something with 'slug' in the JS file, you could do something like this:
if(Meteor.isClient) {
Template.innerTemplate.helpers({
upperCaseSlug() {
return this.slug.toUpperCase();
}
});
}
Then, you could refer to upperCaseSlug in your template, like thus:
<template name=innerTemplate>
<li>{{upperCaseSlug}}</li>
</template>
A few things about Meteor:
You should never see a pattern such as:
<script type="text/javascript">
...some code
</script>
Because Meteor combines all your js files into one big file and includes it automatically in your app. You should never have to declare your own script in this way.
Secondly, you should never have to get the value of a data object by reading the DOM. The data context of each template gives you your data in the variable this.
In either a helper or template event you can refer to this and be assured that you're going to get exactly the data being displayed in that instance of the template.
Having now seen your template code it's now apparent that your template has no data context - you set the data context inside your {{#with post}} and its associated helper but that doesn't end up creating the this you need one level below.
So... #Nathan was on the right track except that he assumed you were iterating over a cursor instead of just looking at a single post.
Take all html you have between your {{#with post}} and {{/with}} and put it in a new template, say postDetail then make your outer template:
<template name="post">
{{#with post}}
{{> postDetail}}
{{/with}}
</template>
Now your postDetail template will get a data context equal to the post object automatically and your helpers can refer to this safely.
Template.postDetail.helper({
slugURI{
return "/"+encodeURI(this.slug);
}
});
Then in your postDetail template you can get the encoded slug with:
<a class="so-facebook" target="_blank" href={{slugURI}}>
I could not find an easy way to explain the following, so I apologize if it is not clear enough.
I have a navigation bar where each item is a category of articles. The navigation item are read from database and can be modified from the back-office.
I get the categories via a AngularJS controller :
app.controller('ApiController', ['$scope', '$http', function($scope, $http) {
$http.get('/categories')
.success(function(categories) {
$scope.categories = categories;
});
}]);
<div class="collapse navbar-collapse" id="target-navbar-main">
<ul class="nav navbar-nav">
<li ng-repeat="category in categories">
<% category.name %>
</li>
</ul>
</div>
In the body of the page, I am using another controller to get articles of a given category but I can't find a way to make the navbar communicate with the articles controller and pass the category of the clicked button.
Thanks for help
I think what you want for the API is a service not a controller. Generally in Angular controllers aren't meant to be sending a bunch of data between each other. Central sets of calls and communications that multiple controllers depend on are put into services. If you were to extract your API calls to a service you could inject that service into that controllers that need to deal with it as necessary. But without seeing more of the code in question it's hard to recommend a good way to do that.
I got it working excellent with one template but ran into an issue trying to replace my inner ng-repeat with another template. Kind of like grouped data or more like nested data.
so let me simplify my html here:
<div data-ng-controller="index.dataGridController" data-ux-datagrid="index.items" class="listA datagrid" data-addons="whichTemplate" grouped="'focus'">
<script type="template/html" data-template-name="default" data-template-item="item">
<div>
<h3>{{ item.obj.name }}</h3>
<!--- instead of
<ul>
<li ng-repeat="listItem in item.focus>{{listitem}}</li>
</uL
-->
</div>
</script>
<script type="template/html" data-template-name="innerFocus" data-template-item="item">
<div>
<ul>
<li>{{item.focus.id}}</li>
</ul>
</div>
</script>
</div>
and the index.items look like this:
[{
"obj": {
"name": "someName"
}
"focus": [
{"id": "something here"},
{"id": "Another etc"}
]
}]
// which template is basically copy and pasted from examples
angular.module('ux').factory('whichTemplate', function () {
return function (inst) {
// now we override it with our method so we decide what template gets displayed for each row.
inst.templateModel.getTemplate = function (item) {
var name = item.focus ? 'innerFocus' : 'default';
// now we get the template from the name.
return inst.templateModel.getTemplateByName(name);
};
};
});
Trying to iterate a list with the focus array. Any ideas? I think it would make for a great example in the docs. Adding a fiddle. http://jsfiddle.net/uftsG/88/
Instead of putting all focus array in one li i'm trying to get them spread out while also having the item.obj.name above the list.
I am not familiar with ux-data grid. If you are set on using it, you can ignore this answer, but I did a small search engine (purely for academic reasons) and i ended up using ng-grid to display the data. I followed the github documentation and ended up boot-strapping #scope.myDefs with the data I needed on the backend using a $scope.getMyData function. In the view all you really need to do is add input fields to get the data, and then a div class with your ng-grid. It's super cool because it ensures the code is modular, and there are no funky functions going on in the view with nested ng-repeats so on and so forth. The only part that gave me trouble was the CSS because I'm not bootstrap savvy yet :) Here's some docs if you end up interested in ng-grid at all.
http://angular-ui.github.io/ng-grid/
I'm using angular-google-maps (http://angular-google-maps.org/) to create a map in my AngularJS application. Within the <google-map> element, I have a <markers> element with the models attribute set to an array which is the result of an $http.get request. For some reason though, the markers never load.
For the sake of knowing the data exists, I setup a simple list with ng-repeat next to the map to output the id of each element in the array when the result is returned and it does indeed populate the list, so I'm not sure why the markers aren't populated when using the <markers> directive. Is it because they're being loaded from an $http.get and I need to do something different?
This is all I'm doing at the moment to get the data from the server. Trucks is a service with finder functions.
Trucks
.findAll()
.then(function(success) {
$scope.trucks = success.data;
}, function(error) {
console.debug(error);
});
My HTML looks like this.
Edit - I read the docs some more and found I need to add the coords attribute = 'self' since the longitude and latitude are part of the model itself, but the markers still don't appear
<div class="row row-fluid">
<div class="google-map col-xs-9" center="map.center" zoom="map.zoom">
<markers models="trucks" do-rebuild-all="true" do-cluster="true" coords="'self'"></markers>
</div>
<div class="col-xs-3">
<ul>
<li ng-repeat="truck in trucks">{{truck.id}}</li>
</ul>
</div>
</div>
Thanks.
I know this seems wierd and it may not solve your issue but the do-cluster attribute should actually be doCluster. Because of the way these directives are built you actually do the Camel case for these. Can you post an example of the data you are getting back? Also, I believe do-rebuild-all would also be doRebuildAll
I have a collection of items, that I would like to stuff into a bootstrap grid. This then looks like this:
<div class="row">
<div class="col-md-8">.col-md-8</div>
<div class="col-md-4">.col-md-4</div>
</div>
<div class="row">
<div class="col-md-8">.col-md-8</div>
<div class="col-md-4">.col-md-4</div>
</div>
So I would need to loop through my collection and adding after every second item
There are two issues:
invalid html! No idea how to get around this
Issues with the module, but I think with some helpers I could get around.
Best would be if there were some examples.
Thanks for any inputs
check out this question. you should be searching for handlebars or spacebars to get better results. Blaze is the template engine; not the template system (if that makes sense.)
How do I populate a bootstrap grid system using handlebars for each command in Meteor.js?
Generically, you need to ensure that your collection is exposed to the template, most likely in a template helper. Then you can iterate the collection items like so:
{{#each templateHelperName}}
<div class="row">
<div class="col-md-8">{{propertyName1}}</div>
<div class="col-md-4">{{propertyName1}}</div>
</div>
{{/each}}
To create a template helper, take a look at the meteor docs; they're quite good.
If this doesn't help, perhaps you can provide some more clarity about what your collection looks like, and how you'd like it displayed. Your code doesn't really give much indication.