display json results with angular - javascript

I'm trying get some json data from a web api. So far Ive gotten the response from the api, Now i'm trying to target a value and insert that value at the end of the youtube link.
movie.component.html
<div *ngIf="movie">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{{movie.title}}</h3>
</div>
<div class="panel-body" >
<div class="row">
<div class="col-md-7">
<img class="thumbnail" src="http://image.tmdb.org/t/p/w500/{{movie.poster_path}}">
</div>
<div class="col-md-5">
<ul class="list-group">
<li class="list-group-item">Genres:<span *ngFor="let genre of movie.genres"> {{genre.name}}</span></li>
<li class="list-group-rel">Release Date: {{movie.release_date | date}}</li>
</ul>
<p>{{movie.overview}}</p>
<br>
**<div *ngIf="videos">
<div *ngFor="let video of videos">
<iframe width="360" height="215" src="https://www.youtube.com/embed/{{video.key}}" frameborder="0" allowfullscreen></iframe>**
</div>
</div>
<h4>Rating</h4>
<p>{{movie.vote_average}} / 10</p>
<a *ngIf="movie.homepage" href="{{movie.homepage}}" target="_blank" class="btn btn-default">Visit Movie Website</a>
</div>
</div>
</div>
</div>
</div>
-----------------
movie.component.ts
export class MovieComponent implements OnInit {
movie:Object;
videos: Object;
constructor(private router:ActivatedRoute, private _movieService:MovieService)
{
}
ngOnInit() {
this.router.params.subscribe((params) =>{
let id = params['id'];
this._movieService.getMovie(id).subscribe(movie =>{
this.movie = movie;
});
});
this.router.params.subscribe((params) =>{
let id = params['id'];
this._movieService.getTrailer(id).subscribe(videos =>{
this.videos = videos;
});
});
}
}
this is the response from Api, I'm trying to target the "key" value and insert it at the end of the youtube link
but i get this error

the problem here that your are using *ngFor for an Object.
*ngFor: is used to iterate arrays.
now the response you have is an object, inside this object you have an array result i believe this is the array you want to iterate.
you just need to change the *ngFor in your template.
...
<div *ngFor="let video of videos.results">
...

Related

filter doesn't show the result on the dom Angular?

What I need to do is to display the filtered array in the DOM once I click on any value from the dropdown. The return from filtered function is right but I couldn't update the DOM.
HTML CODE
This is my side dropdown list that I take the value from
<div class="col-md-3">
<div class="widget">
<h4 class="widget-title">Sort By</h4>
<div>
<select class="form-control" (change)="selectChangeHandler($event)">
<option value="Man">Man</option>
<option value="Women">Women</option>
<option value="Accessories">Accessories</option>
<option value="Shoes">Shoes</option>
</select>
</div>
</div>
</div>
Table that shows the results on DOM take the value from above dropdown list to be able to show them by category. Unfortunately the DOM doesn't change (I used NGX pagination library), please see my TS code that sends the filtered array to the loop? So, I don't understand why it didn't update.
<div class="col-md-9">
<div class="row" id="top">
<div class="col-md-4" *ngFor="let item of collection | paginate: { itemsPerPage: 100, currentPage: p ,id: 'foo' }">
<div class="product-item">
<div class="product-thumb">
<span class="bage">Sale</span>
<img class="img-responsive" src="https://via.placeholder.com/150" alt="product-img" />
<div class="preview-meta">
<ul>
<li>
<span data-toggle="modal" data-target="#product-modal">
<i class="fas fa-search"></i>
</span>
</li>
<li>
</i>
</li>
<li>
<i class="fas fa-shopping-cart"></i>
</li>
</ul>
</div>
</div>
<div class="product-content">
<h4>{{item.name}}</h4>
<p class="price">{{item.price}}</p>
</div>
</div>
</div>
Type Script Code
export class AllproductsComponent implements OnInit {
allProducts:any[]=[]
filteredData=[...this.allProducts]
p: number = 1;
collection: any[] = this.filteredData;
constructor(private _allproducts:ProductService) {
console.log(this.collection);
}
ngOnInit(): void {
this.getAllProducts()
}
getAllProducts():any{
this._allproducts.getAllproducts().subscribe(res=>{
console.log(res.data);
this.allProducts = res.data
this.collection =res.data
})
}
pageChanged(pee:number){
document.getElementById("top").scrollIntoView()
}
selectChangeHandler(value:any){
console.log(value.target.value);
console.log(this.filteredData);
this.filteredData = this.allProducts.filter(key=>{
if(value.target.value === "Man"){
if(key.price > 20)return this.allProducts
}else if(value.target.value === "Women"){
if(key.price < 20) return this.allProducts
}else {
return this.allProducts
}
})
console.log(this.filteredData);
}
}
I appreciate your help, thanks a lot.
allProducts:any[]=[]
filteredData=[...this.allProducts]
collection: any[] = this.filteredData;
you are initializing data before it is called from your api , so it's normal it will never work. You have to reinitialize it inside your method
this._allproducts.getAllproducts().subscribe(res=>{ ..});

How to display nested JSON objects with a changing string in Angular 6

Got a very hard problem to solve and no clue how to tackle it. I'm coding in Angular 6.
To my problem, this is my JSON file. I can easily access data like "id" or "certificate. But I want to display the nested remainingCounts which are left on the ticket and here comes the next problem: the ID before the number of the remainingCounts always matches to the appointmentTypeIDs. How can I tell my Angular Frontend to display always all data icluded in the remainingCounts array?
[
{
"id":9073111,
"certificate":"A4245322",
"productID":425193,
"appointmentTypeIDs":[
5780379
],
"remainingCounts":{
"5780379":10
}
},
{
"id":9073113,
"certificate":"0BE0C148",
"productID":435370,
"appointmentTypeIDs":[
5780416
],
"remainingCounts":{
"5780416":50
}
},
{
"id":9073115,
"certificate":"E72984C2",
"productID":435376,
"appointmentTypeIDs":[
5780421
],
"remainingCounts":{
"5780421":100
}
}
]
My certificate.ts:
export class CertificatesComponent implements OnInit {
private certificates: Array<object> = [];
pageTitle = 'Meine Zertifikate';
email = this.auth.userProfile.name;
constructor(
private title: Title,
private apiService: APIService,
public auth: AuthService
) {}
ngOnInit() {
this.title.setTitle(this.pageTitle);
this.getData();
}
public getData() {
this.apiService
.getCertificatesByUser(this.email)
.subscribe((data: Array<object>) => {
this.certificates = data;
console.log(data);
});
}
}
Any my HTML template:
<div class="ui cards" *ngFor="let certificate of this.certificates">
<div class="card">
<div class="content">
<div class="header">{{certificate.name}}</div>
<div class="meta">{{certificate.email}}</div>
<div class="description">
Verbleibende Termine Ihrer {{certificate.name}}-Karte:
<span *ngFor="let remainingCount of certificates.remainingCounts">
{{remainingCount}}
</span>
</div>
</div>
<sui-progress class="bottom attached indicating active" [value]="80"></sui-progress>
</div>
</div>
First of all remainingCounts is not an array as per the JSON data you've provided. It's just another object.
You could just display using dot(.) Operator as you do it for other properties without ngFor
<div class="ui cards" *ngFor="let certificate of this.certificates"> <div class="card"> <div class="content"> <div class="header">{{certificate.name}}</div> <div class="meta">{{certificate.email}}</div> <div class="description"> Verbleibende Termine Ihrer {{certificate.name}}-Karte: {{certificate.remainingCount}} </div> </div> <sui-progress class="bottom attached indicating active" [value]="80"></sui-progress> </div> </div>
STACKBLITZ DEMO

How to add divs with some classess to another div (inside each other) in html / javascript

I want to list my products from database by clicking on category in html/view.
Firstly I created it in HTML (static) just to check how this is going to look, and it looks lik this:
Here is my html:
<div class="col-md-8" style="margin-top: -15px;">
<div class="products row">
<div class="col-md-3">
<div class="product-holder">
<img class="img-responsive" src="images/coke.png">
<p class="product-title">
Product no1
</p>
</div>
</div>
<div class="col-md-3">
<div class="product-holder">
<img class="img-responsive" src="images/pepsi.png">
<p class="product-title">
Product no2
</p>
</div>
</div>
<div class="col-md-3">
<div class="product-holder">
<img class="img-responsive" src="images/coffe.png">
<p class="product-title">
Product no3
</p>
</div>
</div>
</div>
</div>
And now I want to create this block dynamically:
<div class="col-md-3">
<div class="product-holder">
<img class="img-responsive" src="images/coffe.png">
<p class="product-title">
Product no N
</p>
</div>
</div>
Here is what I've tried so far:
<script>
function onSelectGroup(Id) {
$.ajax({
method: "GET",
url: "Products/GetProductsByCategoryId",
data: { categoryId: Id }
})
.done(function (response) {
//In response I am getting my products, looping through them to create divs like in code above
for (var i = 0; i < response.length; i++) {
//<div class="col-md-3">
// <div class="article-holder">
// <img class="img-responsive" src="images/picture_not_available_400-300.png">
// <p class="product-title">
// Product no 1
// </p>
// </div>
// </div>
//Trying to append it to my .product class because it's parent of this divs above
$(".products").append('<div class="col-md-3"></div>');
$(".products).appendChild('<div class="article-holder"></div>');
}
})};
</script>
But this is not working unfortunatelly... I tried few another things, but this appendings are not working as expected :/
Thanks guys for any help
Cheers
There are many answers posted for the question which might solve the issue with the javascript code. I am posting a different approach as OP specifically requested for it in the comments.
At times, i do not like to build complex HTML markup in javascript with jQuery ( i afraid i might make typos (missing "" or ' etc..). In that case, i would like to have my action method return a view result (the HTML markup) as the response of my ajax call and i can simply update the DOM with that as needed.
public ActionResult GetProductsByCategoryId(int categoryId)
{
var p = db.Products.Where(a=>a.CategoryId==categoryId).ToList();
return PartialView("ProductList",p);
}
Now i will have a partial view called ProductList.cshtml, which is strongly typed to a list of products and i can loop through the items passed to it and render whatever markup i want.
Here is a simple example where i am rendering a div with css class col-md-3 for each item in the collection passed to it. You can update it to render whatever markup you want to render.
#model List<Product>
#foreach (var item in Model)
{
<div class="col-md-3">
<div class="product-holder">
<img class="img-responsive" src="#item.ImageUrl">
<p class="product-title">
#item.Name
</p>
</div>
</div>
}
Now all i have to do is, call this action method, and use the response to update my DOM. Let's give an Id to the container div which we will update
<div class="col-md-8" >
<div id="product-list" class="products row">
</div>
</div>
Now when the ajax call receives a response from server, update the inner html of the DOM element with Id product-list
$.ajax({
method: "GET",
url: "#Url.Action("GetProductsByCategoryId","Products")",
data: { categoryId: 2345 }
})
.done(function(response) {
$("#product-list").html(response);
}).fail(function(a, a, e) {
alert(e);
});
Keep in mind that, now you are getting a bigger payload (the resulting HTML)
from the server compared to the JSON data. So use this approach as you feel appropriate to do so. With this approach, i can use the C# methods in my partial view (For example, to build the path to an image in a location/ use Html helper methods etc)
I you create the dom element like any string, and append it to the container
function onSelectGroup(Id) {
//In response I am getting my products, looping through them to create divs like in code above
for (var i = 0; i <10; i++) {
let item = `<div class="col-md-3">
<div class="article-holder">
<img class="img-responsive" src="images/picture_not_available_400-300.png">
<p class="product-title">
Product no ${i}
</p>
</div>
</div>`
//Trying to append it to my .product class because it's parent of this divs above
$(".products").append(item);
}
};
onSelectGroup();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="col-md-8" style="margin-top: -15px;">
<div class="products row">
<div class="col-md-3">
<div class="product-holder">
<img class="img-responsive" src="images/coke.png">
<p class="product-title">
Product no1
</p>
</div>
</div>
<div class="col-md-3">
<div class="product-holder">
<img class="img-responsive" src="images/pepsi.png">
<p class="product-title">
Product no2
</p>
</div>
</div>
<div class="col-md-3">
<div class="product-holder">
<img class="img-responsive" src="images/coffe.png">
<p class="product-title">
Product no3
</p>
</div>
</div>
</div>
</div>
You can create a new element with jquery and fill it properly
for (var i = 0; i < response.length; i++) {
//<div class="col-md-3">
// <div class="article-holder">
// <img class="img-responsive" src="images/picture_not_available_400-300.png">
// <p class="product-title">
// Product no 1
// </p>
// </div>
// </div>
//Trying to append it to my .product class because it's parent of this divs above
var newelem = $('<div class="col-md-3"></div>');
var artholder = $('<div class="article-holder"></div>');
newelem.append(artholder);
artholder.append(<your-image><your article title>);
}
You was close; all you needed to do was create an element for each item in the results object. I've used test data in the example.
https://jsfiddle.net/tw0vrpyy/
var response = {
item1: {
id: "id1",
title: "title1",
img: "img_src1.jpg"
},
item2: {
id: "id2",
title: "title2",
img: "img_src2.jpg"
}
};
var product = document.getElementsByClassName('response')[0];
Object.keys(response).forEach(function(key) {
var el = '<div class="col-md-3">' +
'<div class="article-holder">' +
'<img class="img-responsive" src="'+ response[key].img +'">' +
'<p class="product-title">' +
response[key].title +
'</p>' +
'</div>' +
'</div>';
product.innerHTML += el;
});

angular2 bootstrap dynamic carousel

I have a dynamic images coming from a json and doing *ngFor to loop through the objs and putting it in a carousel using bootstrap carousel, but I want to put a readmore link within the *ngFor so each item will have a read more.
I can't figure out how to do when a user click "readmore" it will scroll to its relative item showing about the image if that makes sense.
<div class="col-sm-4" *ngFor="let journey of Journey">
<div class="journey_block">
<div class="icon-workflow">
<div class="view view-fourth">
<img src="{{ journey.imageName }}" alt="">
<div class="mask">
Read More
</div>
</div>
<h4 class="journey_title">
<a [href]="journey.journey_url" *ngIf="journey.journey_url != 'javascript:;' " class="float-shadow">
{{journey.title}}
</a>
</h4>
</div>
</div>
My attempt is I thought I would then need to do for loop, I have 5 items in total in the json data.
getImg() {
this.http.get('./journey.json')
.map((res:Response) => res.json())
.subscribe(data => {
if(data) {
var jsonObj = JSON.parse(JSON.stringify(data));
this.Journey = jsonObj.journey;
for (var i = 0; i < this.Journey.length; i++) {
var element = this.Journey[i];
this.objCount = element;
console.log(this.objCount);
}
}
});
};
View full html structure of the carousel
Carousel structure
You need to have the index inside of the loop for making the data-slide-to attribute unique. This could be done by the predefined Angular2 value index.
Example
<!-- Angular 2.0 -->
<ul>
<li *ngFor="let item of items; let i = index">
{{i}} {{item}}
</li>
</ul>
In your code:
<div class="col-sm-4" *ngFor="let journey of Journey; let i = index">
<div class="journey_block">
<div class="icon-workflow">
<div class="view view-fourth">
<img src="{{ journey.imageName }}" alt="">
<div class="mask">
Read More
</div>
</div>
<h4 class="journey_title">
<a [href]="journey.journey_url" *ngIf="journey.journey_url != 'javascript:;' " class="float-shadow">
{{journey.title}}
</a>
</h4>
</div>
</div>

Knockout.js : ObservableArray with ObservableArrays inside?

I'm using this plugin called Dragula which needs an ObservableArray as a source for the data..
HTML/Knockout-bindings
<div class="widget-container">
<div class="widget-content visible" id="team-setup">
<div class="header">
<p>Lagoppsett</p>
<p></p>
</div>
<div class="col-sm-12">
<div class="row">
<div class="widget-container">
<div class="col-xs-6 widget-content visible">
<div class="header">
<p>Tilgjengelige spillere</p>
<p></p>
</div>
<div class="player-card-container-mini" data-bind="dragula: { data: availablePlayers, group: 'playerz' } ">
<div class="player-card-mini">
<div class="player-card-left">
<div class="player-avatar" style="margin-left: 85%;">
<img src="Content/Images/player-female.png" id="imgAvatar" runat="server" />
<div class="player-shirt-no" data-bind="text: ShirtNo"></div>
</div>
</div>
<div class="player-card-subtext">
<div class="player-text">
<div class="player-card-header-small" data-bind="text: PlayerName"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-xs-6 widget-content visible">
<div class="header">
<p>Lag</p>
<p></p>
</div>
<div data-bind="foreach: teamsetup">
<div data-bind="foreach: SubTeams">
<h1 data-bind="text: TeamSubName"></h1>
<div class="player-card-container-mini" data-bind="dragula: { data: Players, group: 'playerz' } " style="border: 1px solid red; min-height:200px">
<div class="player-card-mini">
<div class="player-card-left">
<div class="player-avatar" style="margin-left: 85%;">
<img src="Content/Images/player-female.png" id="img1" runat="server" />
<div class="player-shirt-no" data-bind="text: ShirtNo"></div>
</div>
</div>
<div class="player-card-subtext">
<div class="player-text">
<div class="player-card-header-small" data-bind="text: PlayerName"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div style="clear:both"> </div>
</div>
</div>
Knockout code :
var TeamSetupViewModel = function () {
var self = this;
self.teamsetup = ko.observableArray();
self.availablePlayers = ko.observableArray();
self.testPlayers = ko.observableArray();
}
var model = new TeamSetupViewModel();
ko.applyBindings(model, document.getElementById("team-setup"));
var uri = 'api/MainPage/GetTeamSetup/' + getQueryVariable("teamId");
$.get(uri,
function (data) {
model.teamsetup(data);
model.availablePlayers(data.AvailablePlayers);
model.testPlayers(data.AvailablePlayers);
console.log(data);
}, 'json');
});
The problem is... that i'm having a ObservableArray at the top node, and i do need ObservableArrays further down in the hierarchy.
model.availablePlayers works fine, but when accessing the other players in the html/ko foreach loops through teamsetup -> SubTeams -> Players it doesn't work due to Players isn't an ObservableArray. (There might be everyting from 1 to 7 SubTeams with players).
So how can i make the Players in each SubTeams an ObservableArray ?
See the image for the datastructure :
You could use Mapping plugin, but if players is the only thing you need, you can do it manually:
Simplify your view model:
var TeamSetupViewModel = function () {
var self = this;
self.availablePlayers = ko.observableArray();
self.subTeams = ko.observableArray();
}
After you get the data from the server, populate the view model converting the array of players on every team to an observable array of players:
$.get(uri,
function (data) {
model.availablePlayers(data.AvailablePlayers);
model.subTeams(data.SubTeams.map(function(t) { t.Players = ko.observableArray(t.Players); return t; }));
}, 'json');
});
Finally, remove the following line in your template (with its closing tag) - nothing to iterate over anymore:
<div data-bind="foreach: teamsetup">
... and update the name of the property in the next line, so it is camel case like in the VM:
<div data-bind="foreach: subTeams">

Categories