Using ng-repeat on a JSON object doesn't work - why? - json

I can't seem to iterate over a JSON object using ng-repeat. I did test it directly by index and it works, but just can't seem to loop and print. What am I doing wrong? JSFiddle link.
Here's my code:
<div ng-app="myApp">
<div ng-controller="Ctrl">
<h3>Upcoming Events</h3>
<ul ng-repeat="event in events">
<li>{{ event.feed.entry.title.$t }}</li>
</ul>
<!-- testing single entry here - it works! -->
<small>{{ events.feed.entry[0].title.$t }}</small>
</div>
</div>
The script:
var app = angular.module('myApp', []);
var feedUrl = 'https://www.google.com/calendar/feeds/ogmda.com_89pas0l9jbhpf053atd83hdj30%40group.calendar.google.com/public/basic?alt=json';
app.controller('Ctrl', function($http, $scope) {
$http.get(feedUrl).success(function(data) {
$scope.events = data;
});
});

That's because you iterate over the whole data returned by the calendar query, and not over the entries themselves. Change your ul to:
<ul ng-repeat="entry in events.feed.entry">
<li>{{ entry.title.$t }}</li>
</ul>

Related

How to create a bullet list from parsed dynamic object

So I have a JSON string foo_json_string:
[{"foo_name":"foo_value"},{"foo_name1":"foo_value1"}]
that I want to parse and show as HTML list.
I used the following approach:
<ul>
<li v-for="item in JSON.parse(foo_json_string)" v-bind:key="item.id">
{{`${item.name} = ${item.value}`}}
</li>
</ul>
This doesn't work. Most likely because item.name and item.value don't exist but I am not sure how to fix that. Any suggestions?
Maybe, you mean like this ?
var respond = [{"foo_name":"foo_value"},{"foo_name1":"foo_value1"}];
$.each(respond, function(k, v){
console.log(v);
$.each(v, function(k1, v1){
$('#out').append('<li>'+v1+'</li>');
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="out"></ul>
You need to access the key of the parsed Object. Use Object.keys() method for getting the key. There is the working snippet below.
new Vue({
el: '#app',
data: {
foo_json_string: '[{"foo_name":"foo_value"},{"foo_name1":"foo_value1"}]',
},
});
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app">
<ul v-for="item in JSON.parse(foo_json_string)">
<li v-for="key in Object.keys(item)">
{{`${key} = ${item[key]}`}}
</li>
</ul>
</div>

For loop and Popup with liquid and jekyll

I want to create a list of modal popups with a for-loop, each of them displaying different text.
The site is created with Jekyll with the Liquid templating engine.
In particular, I want to create the list of my scientific publications, for each of them with 2 icons: one for the bibtex entry and one for the abstract. This information is stored in a yaml file.
I m following this simple tutorial for modal popups.
The popups work, but the text is the same for all the entries. How is possible to generate independent modal popups?
This is the html
{% for papers in papers %}
{% for content in paper.papers %}
<a title="{{content.name}}"><i class='{{content.icon}}' data-modal-target="#modal"></i></a>
<div class="modal" id="modal">
<div class="modal-header">
<div class="title">{{content.name}}</div>
<button data-close-button class="close-button">×</button>
</div>
<!-- text to display -->
<div class="modal-body">{{content.text}}</div>
</div>
{% endfor %}
{% endfor %}
and this is the Javascript code:
const openModalIcons = document.querySelectorAll('[data-modal-target]')
const closeModalButtons = document.querySelectorAll('[data-close-button]')
const overlay = document.getElementById('overlay')
openModalIcons.forEach(icon => {
icon.addEventListener('click', () => {
const modal = document.querySelector(icon.dataset.modalTarget)
openModal(modal)
})
})
function openModal(modal) {
if (modal == null) return
modal.classList.add('active')
overlay.classList.add('active')
}
closeModalButtons.forEach(button => {
button.addEventListener('click', () => {
const modal = button.closest('.modal')
closeModal(modal)
})
})
function closeModal(modal) {
if (modal == null) return
modal.classList.remove('active')
overlay.classList.remove('active')
}
overlay.addEventListener('click', () => {
const modals = document.querySelectorAll('.modal.active')
modals.forEach(modal => {
closeModal(modal)
})
})
The problem is that all your modals have id="modal", so the selector #modal is probably always selecting the first one. The id attribute should be unique in the entire document.
Something like this should work:
{% for papers in papers %}
{% for content in paper.papers %}
<a title="{{content.name}}"><i class='{{content.icon}}' data-modal-target="#paperModal{{forloop.parentloop.counter}}_{{forloop.counter}}"></i></a>
<div class="modal" id="paperModal{{forloop.parentloop.counter}}_{{forloop.counter}}">
<div class="modal-header">
<div class="title">{{content.name}}</div>
<button data-close-button class="close-button">×</button>
</div>
<!-- text to display -->
<div class="modal-body">{{content.text}}</div>
</div>
{% endfor %}
{% endfor %}
Instead of the for loop counter, you could also use the paper name as the ID (as long as it's unique), e.g. id="paperModal_{{content.name | slugify}}".
Edit: Edited the snippet to use forloop.counter and account for the nested for loop.

onclick Function not working independently for each element of ng-repeat

I have used ng-repeat to print out some divs. In each div I have given a p tag which says view more. On clicking that I want that the particular div that has been clicked for view more shows the data that I have put to be shown on that click. But instead all the divs are triggered together on clickin any view more p tag. Also in the content that will be shown on click I have a p tag that says view less and it hides back that content and that does the same thing. How do I make them work independently?
here is the html and angularjs code
<div ng-repeat="rent in RentSummDtl" class="rentSummCard">
<div ng-if="rent.property_id == propId">
<p id="rentSummPropName">{{ rent.month_yr }}</p>
<p class="rentSummDetl">{{ rent.propertypayamount }}</p>
<p class="rentSummDetl">{{ rent.calculatedpropertypayamount }}</p>
<p class="rentSummDetl" ng-click="isShowHide('show')" ng-show="viewMore">View More <i class="fas fa-chevron-down"></i></p>
<div ng-show="showrentDtl">
<p class="rentSummDetl">{{ rent.addition }}</p>
<p class="rentSummDetl">{{ rent.deduction }}</p>
<p class="rentSummDetl">{{ rent.percentage | number:2 }}</p>
<p class="rentSummDetl">{{ rent.ad_remark }}</p>
<p class="rentSummDetl">{{ rent.de_remark }}</p>
<p ng-click="isShowHide('hide')">View Less <i class="fas fa-chevron-up"></i></p>
</div>
</div>
</div>
$scope.showrentDtl = false;
$scope.hiderentDtl = false;
$scope.viewMore = true;
$scope.isShowHide = function (param) {
if(param == "show"){
$scope.showrentDtl = true;
$scope.hiderentDtl = false;
$scope.viewMore = false;
}
else if(param == "hide"){
$scope.showrentDtl = false;
$scope.hiderentDtl = true;
$scope.viewMore = true;
}
else{
$scope.showrentDtl = false;
$scope.hiderentDtl = false;
}
}
Is this because I have put the ng-click inside the ng-repeat and hence it works for all of them at a time together. But then how would I keep the view more inside each div if I keep it outside the ng-repeat.
Since ng-repeat creates its own local scope, you can take advantage of this by defining a variable that is local to each item in your ng-repeat. To do this simply remove your viewMore variable from your controller and set its value directly in the view. Here's a simple example to illustrate this technique.
angular.module('app', [])
.controller('ctrl', function($scope) {
$scope.items = [];
for (var i = 1; i <= 5; i++) {
var item = {
name: 'Item ' + i,
details: 'Here are some details for Item ' + i + ' so that we have something to show in the view.'
}
$scope.items.push(item);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<div ng-repeat="item in items">
<h3>{{ item.name }}</h3>
<button ng-click="viewMore = !viewMore">
<span ng-hide="viewMore">Show</span>
<span ng-show="viewMore">Hide</span>
Details
</button>
<div ng-show="viewMore">
{{ item.details }}
<a ng-click="viewMore = false"
style="cursor: pointer; color: orange;">[hide]</a>
</div>
</div>
</div>

Angular 2-way binding not working

Below is my code.2 way binding is not working as expected. Can you please point-out the mistake
<div id="list" class="form-group">
<label for="attach" class="col-xs-2 control-label">{{ resource["gve.common.attach"] }}</label>
<div class="col-xs-5">
<ol class="marTop10">
<li class="exactFit" ng-repeat="files in attachList">{{ files.fileName }}</li>
</ol>
</div>
</div>
$scope.populateView = function()
{
$rootScope.inputSpin = false;
$rootScope.modifiedCaseData = $scope.problem;
$scope.showReviewBtn = $rootScope.showReviewBtn;
$scope.attachList = [];
$scope.attachList.push({fileId:"100",fileName:"Test.pdf"});
for(i in $scope.attachList) {
console.log (i, $scope.attachList[i]);
}
};
fileName is not getting displayed in HTML {{files.fileName}} even though {fileId:"100",fileName:"Test.pdf"} is added to $scope.attachList
EDIT 1: I am sorry for not mentioning those details. ng-controller is already defined and populateView() is called from a different function.
EDIT 2: From console.log .
09:56:17.486 problemCtrl.js?gccm=1.0:185 0 Object {fileId: 100, fileName: "untitled 8.txt"}fileId: 100fileName: "untitled 8.txt"
Are you missing the ng-controller directive or it is already defined elsewhere?
Make sure you are calling the populateView()
DEMO
var app = angular.module('test',[]);
app.controller('testCtrl',function($scope){
$scope.populateView = function()
{
$scope.attachList = []; $scope.attachList.push({fileId:"100",fileName:"Test.pdf"});
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test" ng-controller="testCtrl" ng-init="populateView()" class="col-xs-5">
<ol class="marTop10">
<li class="exactFit" ng-repeat="files in attachList">{{ files.fileName }}</li>
</ol>
</div>

Render one template (no ng-repeat)

I am just starting off with angular, but basically I want to render one set of templates with ng repeat:
<ion-item ng-repeat="item in items" ng-click="loadSingle(item)">
Hello, {{item.name}}!
</ion-item>
and then later I want to render the object in a different template if someone clicks on it:
<div>
<h1>{{ item.name }}</h1>
<h2>{{ item.detail }}</h2>
</div>
How do I do this? With jQuery/underscore I would just have the separate template loaded and feed it the json object (item) but I can't seem to find any documentation on how to do the templating without the ng-repeat. I'm a little confused. Thanks!
I would define loadSingle() as a method that would put the specific item onto the scope. Then I would define another section in the HTML to display the selected item.
JavaScript
app.controller('ctrl', function($scope){
$scope.loadSingle = function(item){
$scope.selectedItem = item;
}
});
HTML
<div ng-show="selectedItem">
<h1>{{ selectedItem.name }}</h1>
<h2>{{ selectedItem.detail }}</h2>
</div>