How to render html data from JSON in a modal angular 8 - javascript

I have a html table stored in a database table. I am fetching the html table using a get request, but for some reason, I cant seem to render the html from the api to the modal.
How I am fetching the html table from the api
async loadReportData(eaCode): Promise<void> {
this.html_content = this.service.getHtmlReport(code);
//this.teamMembersData = await this.re.getTeamMembers(this.currentProjectId, teamId);
console.log(this.service.getHtmlReport(code))
}
my angular modal where am trying to render the html table
<ng-template #viewTeamModal let-modal>
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-body">
<div class="row">
<div class="col-11">
<h4 class="card-title" style="color: black;"><span class="lstick"></span>Report</h4>
</div>
<div class="col-1">
<button type="button" class="close" label="Close" (click)="modal.dismiss('Cross click');">
<span aria-hidden="true">×</span>
</button>
</div>
</div>
<div class="row">
<div class="table-responsive">
</div>
</div>
</div>
</div>
</div>
</div>
</ng-template>
the html table being fetched from the api
<table style="width:100%">
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Age</th>
</tr>
<tr>
<td>Jill</td>
<td>Smith</td>
<td>50</td>
</tr>
<tr>
<td>Eve</td>
<td>Jackson</td>
<td>94</td>
</tr>
</table>
when I try to console log I get
Observable
operator: MapOperator {thisArg: undefined, project: ƒ}
source: Observable {_isScalar: false, source: Observable, operator: MapOperator}
_isScalar: false
__proto__: Object
what am I doing wrong. Thank you in advance

Nothing wrong, just that it seems like the method this.service.getHtmlReport(code) returns an Observable.
This will log the actual value:
this.service.getHtmlReport(code).subscribe(code => {
console.log(code);
})
Is it recommended where possible to handle the subscription using the async pipe. I put it inside OnInit but that is just for the sake of example, you can use it where you need:
public code: Observable;
ngOnInit() {
...
this.code = this.service.getHtml(code);
}
and inside the template:
<div class="table-responsive" [innerHTML]="code | async"></div>
If you haven't read about observables these resources might be useful for start:
https://angular.io/guide/observables
https://angular.io/guide/observables#subscribing
https://malcoded.com/posts/angular-async-pipe/
https://gist.github.com/staltz/868e7e9bc2a7b8c1f754

Related

Accessing HTML Element after Adding with innerHtml

I am adding the data received as a result of a request to my page as follows.
showMovieInfo(movies) {
this.tableDiv.innerHTML = "";
movies.forEach(movie => {
this.tableDiv.innerHTML +=
`
<table class="table align-middle mb-0 bg-white">
<thead class="bg-light">
<tr>
<th>Movie Name</th>
<th>Position</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="d-flex align-items-center">
<img src="${movie.image}"
alt="" style="width: 120px; height: 120px" class="rounded-circle" />
<div class="ms-3">
<p class="fw-bold mb-1">${movie.title}</p>
<p class="text-muted mb-0">${movie.description}</p>
</div>
</div>
</td>
<td>
<button type="button" id="showonmap" class="btn btn-link btn-sm btn-rounded">
Show on map
</button>
</td>
</tr>
</tbody>
</table>`
});
}
then i want to add addEventListener to buttons with id="showonmap".But I am getting an error and when I click the buttons, any function does not work.
To support the comment made above regarding the delegated event listener I quickly rattled up this simple demo that slightly rewrites your original class method as a standalone function so that you can see the effect in action. As the event handler is assigned to a parent element within the DOM which does exist when the page is loaded you can use the event to identify which button ( or other element ) was clicked and from there do whatever operations are required.
const movies = [{
image: 'http://t1.gstatic.com/images?q=tbn:ANd9GcQsJW_I8KPZiq4mXcpRCd8uKBsUMR4Gz691k6gwEiLqVOoTl8pf',
title: 'The Life of Brian',
description: 'this is a great movie'
},
{
image: 'https://m.media-amazon.com/images/M/MV5BOTI4MDdjMmUtOTZhOS00MTYwLWEyZTUtYTdhMTQxNGM1YTUxXkEyXkFqcGdeQXVyMzg1ODEwNQ##._V1_UX140_CR0,0,140,209_AL_.jpg',
title: 'The Wasp Woman',
description: 'this is a terrible movie'
}
];
// slightly re-written as no longer part of a class/object
showMovieInfo = (movies) => {
// exlicitly define this.tableDiv here rather than in constructor earlier ( & not shown )
this.tableDiv = document.getElementById('movies');
this.tableDiv.innerHTML = "";
movies.forEach(movie => {
this.tableDiv.innerHTML +=
`
<table class="table align-middle mb-0 bg-white">
<thead class="bg-light">
<tr>
<th>Movie Name</th>
<th>Position</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="d-flex align-items-center">
<img src="${movie.image}"
alt="" style="width: 120px; height: 120px" class="rounded-circle" />
<div class="ms-3">
<p class="fw-bold mb-1">${movie.title}</p>
<p class="text-muted mb-0">${movie.description}</p>
</div>
</div>
</td>
<td><!-- modified id to data-id and added data-title for demo -->
<button type="button" data-id="showonmap" data-title="${movie.title}" class="btn btn-link btn-sm btn-rounded">
Show on map
</button>
</td>
</tr>
</tbody>
</table>`;
});
this.tableDiv.addEventListener('click', function(e) {
if (e.target != e.currentTarget && e.target.tagName == 'BUTTON' && e.target.hasAttribute('data-id')) {
alert(e.target.dataset.title);
// ... here you would do other operations to actually "view on map"
// ... etc
}
})
}
showMovieInfo(movies);
<div id='movies'></div>

Protractor find a certain value inside td class

I have been looking on many different examples how to iterate a table.
If I am using code below for selenium I get exactly what I want.
driver.findElement(By.xpath("//td[contains(.,'Apple Pomace')]"));
though I would like to instead to iterate the code and find the value below:
<td class="ng-binding">Apple Pomace</td>
Notice there are Apple Pomace in two places
See image
there is my table:
<div class="col-md-8 col-md-offset-2 col-sm-10 col-sm-offset-1">
<h3 ng-show="searchQuery" class="page-header page-header-sm"><span translate="TITLE_SEARCH_RESULTS" class="ng-scope">Search Results</span> <span class="label label-default ng-binding" ng-bind-html="searchQuery">Apple Pomace</span></h3>
<h3 ng-show="!searchQuery" class="page-header page-header-sm ng-scope ng-hide" translate="TITLE_ALL_PRODUCTS">All Products</h3>
<div class="alert-info ng-hide" ng-show="confirmation">
<p class="ng-binding"></p>
</div>
<table class="table table-striped table-bordered table-condensed">
<tbody><tr>
<th translate="LABEL_IMAGE" class="ng-scope">Image</th>
<th translate="LABEL_PRODUCT" class="ng-scope">Product</th>
<th translate="LABEL_DESCRIPTION" class="ng-scope">Description</th>
<th translate="LABEL_PRICE" class="ng-scope">Price</th>
<th></th>
</tr>
<!-- ngRepeat: product in products --><tr data-ng-repeat="product in products" class="ng-scope" style="">
<td><img src="/public/images/products/apple_pressings.jpg" class="img-responsive img-thumbnail" style="width: 200px" ng-click="showDetail(product.id)"></td>
<td class="ng-binding">Apple Pomace</td> //here is the item I want to fetch 'Apple Pomace'
<td><div ng-bind-html="product.description" class="ng-binding">Finest pressings of apples. Allergy disclaimer: Might contain traces of worms. Can be sent back to us for recycling.</div></td>
<td class="ng-binding">0.89</td>
<td>
<div class="btn-group">
<a class="btn btn-default btn-xs" ng-click="showDetail(product.id)"><i class="fa fa-eye"></i></a>
<a class="btn btn-default btn-xs ng-hide" ng-click="addToBasket(product.id)" ng-show="isLoggedIn()"><i class="fa fa-cart-plus"></i></a>
</div>
</td>
</tr><!-- end ngRepeat: product in products -->
</tbody></table>
</div>
I hade made following code but it's not correct in my opinion.
element.all(by.css('.ng-binding')).each(function(element, index)
{
element.getText().then(function (text)
{
});
})
notice I got 'Apple Pomace' in two places that's why its important to iterate through the td-class 'ng-binding'.
Could someone help me
Thank you in advance
In case if you want to just access the td you can use this:
element(by.cssContainingText('.table td', 'Apple Pomace'))
In case if you would like to filter the rows in the table by the product and get the element you can use below code snippet:
element.all(by.repeater('product in products')).filter(function(elem, index) {
return elem.element(by.cssContainingText('td', 'Apple Pomace')).isPresent();
}).first();

Bootstrap Accordion in Angular with dynamic length

I am learning Angular 4 in combination with Bootstrap.
The idea is to receive an array of lists from my backend server, which works fine, and to display each list in one single accordion (collapse).
My problem is the following: As the array of lists varies in length, I have to create the elements dynamically, which creates this error:
zone.js:569 Unhandled Promise rejection: Template parse errors:
Can't bind to 'target' since it isn't a known property of 'tr'. (" <tbody>
<tr *ngFor="let listObj of lists" class="panel panel-default" data-toggle="collapse" [ERROR ->]data-target="#collapse{{listObj.index}}">
<td><div class="panel-group">
<div class="p"): ng:///AppModule/TestComponent.html#8:90 ; Zone: <root> ; Task: Promise.then ; Value: Error: Template parse errors:
Can't bind to 'target' since it isn't a known property of 'tr'. (" <tbody>
<tr *ngFor="let listObj of lists" class="panel panel-default" data-toggle="collapse" [ERROR ->]data-target="#collapse{{listObj.index}}">
<td><div class="panel-group">
<div class="p"): ng:///AppModule/TestComponent.html#8:90
How it should look like:Tested with hardcoded HTML
My HTML:
<table class="table table-hover ">
<thead>
<tr>
<th>Description</th>
<th>Author</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let listObj of lists" class="panel panel-default" data-toggle="collapse" data-target="#collapse{{listObj.index}}">
<td><div class="panel-group">
<div class="panel-heading">
{{listObj.list.listDescription}}
{{listObj.index}}
</div>
<div id="collapse{{listObj.index}}" class="panel-collapse collapse">
<ul class="list-group">
<li *ngFor="let item of listObj.list.listItems" class="list-group-item col-lg-12">{{item}}</li>
</ul>
</div>
</div>
</td>
<td>{{listObj.list.listAuthorName}}</td>
<td>
<div class="input-group">
<input type="text" class="form-control" #listAdd>
<span class="input-group-btn">
<button (click)="onClickAddItem(list.listId, listAdd.value)" class="btn btn-default" type="button">add</button>
<button class="btn btn-danger" type="button">Delete</button>
</span>
</div>
</td>
</tr>
</tbody>
</table>
The array of list-objects is in standard JSON-format
also exuse my english and thank you for your help
I guess you are looking for attribute binding like
[attr.data-target]="'#collapse' + listObj.index"

Angularjs controller call looping

I have a controller which is as following
var app = angular.module('StudentProgram', []);
app.controller('mycontroller', function($scope){
$scope.details=[
{name1:"TIER 1 - CORE FOUNDATIONS", subcategory1:[
{name2:"Critical Reading and Writing", subcategory2:[
{course:"HIST 1301",term:"Spring 2012",credit:"3.0",grade:"B"},
{course:"ENGL 1301",term:"Spring 2012",credit:"3.0",grade:"A"}
]},
{name2:"Speaking and Listening", subcategory2:[
{course:"HIST 1301",term:"Spring 2012",credit:"3.0",grade:"B"},
{course:"ENGL 1301",term:"Spring 2012",credit:"3.0",grade:"A"}
]}
]},
{name1:"TIER 2 - CORE DOMAINS", subcategory1:[
{name2:"Critical Reading and Writing", subcategory2:[
{course:"HIST 1301",term:"Spring 2012",credit:"3.0",grade:"B"},
{course:"ENGL 1301",term:"Spring 2012",credit:"3.0",grade:"A"}
]}
]}
];
});
I have defined a div to call the json above in loops using ng-repeat:
<div ng-controller="mycontroller" class="panel panel-primary">
<div ng-repeat="title in details">
<div class="panel-heading">
<h3 class="panel-title">{{title.name1}}</h3>
</div>
<div ng-repeat="subtitle in details" class="panel-body">
<div class="container">
<h4><strong>{{subtitle.name2}}</strong></h4>
<table class="table table-hover" style="width:700px;">
<tr>
<th>Course</th>
<th>Term</th>
<th>Credit</th>
<th>Grade</th>
</tr>
<tr ng-repeat="detail in details">
<td>{{detail.course}}</td>
<td>{{detail.term}}</td>
<td>{{detail.credit}}</td>
<td>{{detail.grade}}</td>
</tr>
</table>
</div>
</div>
</div>
</div>
I would like to call the div using ng-repeat in such a way that it looks like the following:
Please help!
your ng-repeat usage was wrong on many part...
here is fixed HTML
<div ng-repeat="detail in details">
<div class="panel-heading">
<h3 class="panel-title">{{detail.name1}}</h3>
</div>
<div ng-repeat="subcategory in detail.subcategory1" class="panel-body">
<div class="container">
<h4>
<strong>{{subcategory.name2}}</strong>
</h4>
<table class="table table-hover" style="width:700px;">
<tbody>
<tr>
<th>Course</th>
<th>Term</th>
<th>Credit</th>
<th>Grade</th>
</tr>
<tr ng-repeat="subcategory2 in subcategory.subcategory2">
<td>{{subcategory2.course}}</td>
<td>{{subcategory2.term}}</td>
<td>{{subcategory2.credit}}</td>
<td>{{subcategory2.grade}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
and here is working PLUNKER...

modal inside an ng-repeat directive causes crash

i am trying to put inside a table abutton that will open a modal.
but no matter which button i click it seems that it tries to open it many times.
i have put the openModal and closeModal inside the main controller.
i believe the problem might be because i am using it inside an ng-repeat?
but in any case i do not know what is going wrong. what am i doing wrong?
i am using this modal:
http://angular-ui.github.io/bootstrap/#/modal
the html code:
<div class="row">
<div class="span4" ng-repeat="court in courts">
<table class="table table-condensed table-bordered table-hover">
<caption><h4>court {{court.records[0].id}}<h4></caption>
<tr>
<th style='text-align:center'>Hour</th>
<th style='text-align:center'>Player 1</th>
<th style='text-align:center'>Player 2</th>
<th></th>
</tr>
<tr ng-repeat="record in court.records">
<td width="50" >{{record.hour}}</td>
<td ng-style="user1Payed(record)" style='text-align:center'>{{record.u1_first}} {{record.u1_last}}</td>
<td ng-style="user2Payed(record)" style='text-align:center'>{{record.u2_first}} {{record.u2_last}}</td>
<td> <!-- options button -->
<button class="btn" ng-click="openModal()">Open me!</button>
<div modal="shouldBeOpen" close="closeModal()" options="opts">
<div class="modal-header">
<h3>I'm a modal!</h3>
</div>
<div class="modal-body">
<ul>
<li ng-repeat="item in items">{{item}}</li>
</ul>
</div>
<div class="modal-footer">
<button class="btn btn-warning cancel" ng-click="closeModal()">Cancel</button>
</div>
</div>
</td> <!-- options button end -->
</tr>
</table>
</div>
</div>
and the controller code:
function CourtsController($scope, $window, $http, CourtsService, $timeout) {
$scope.openModal = function () {
$scope.shouldBeOpen = true;
};
$scope.closeModal = function () {
$scope.closeMsg = 'I was closed at: ' + new Date();
$scope.shouldBeOpen = false;
};
$scope.items = [
"Guest Payment",
"Member Payment",
"League (no payment)",
"no Payment"
];
$scope.opts = {
backdropFade: true,
dialogFade:true
};
Move you modal div of the ng-repeat and set $scope variable according your openModal().

Categories

Resources