I have a list of elements displayed on my HTML page. For whatever element selected, I wish to retrieve the corresponding data from the firebase database.
Here's the code of how I am displaying the list on the HTML page. These items are retrieved from firebase.
<div class="list-group " *ngFor="let year of years | async">
<a routerLink="records" routerLinkActive="active">
<mdb-icon fas icon="table" class="mr-3"></mdb-icon>{{year.key}}</a>
</div>
routerLink="records" , Records.html is where I would like to display the corresponding data.
Records is a html page where...based on the selected "year" , the data should be dynamically loaded.
I would use two services
one for your http calls (apiService) and one for storing the datas in your app (in that case dataService)
in your actual ts
years:any[] = []
//you can trigger that with ngOnInit or other events
this.apiService.getYears.subscribe(
data => {
this.dataService.setYears(data)
this.years = this.dataService.getYears();
}
)
in your html (no more async just data)
<div class="list-group " *ngFor="let year of years | async">
<a [routerLink]="['records/'+ year.key]" routerLinkActive="active">
<mdb-icon fas icon="table" class="mr-3"></mdb-icon>{{year.key}}</a>
</div>
then in your record component
year:any = undefined
//check for ActivatedRoute.params for retrieving the key (here `yearKey`) in your url
ngOnInit(){
if (!(this.year = this.dataService.getYear(yearKey)))
this.apiService.getYear(yearKey).subscribe(
data => this.year = data
)
}
REFERENCES
Services
Related
I am making list of button that will lead to different YouTube videos on ReactJs page. The issue is that when I map the links from json file (which contains video links), all the buttons get the last link of the mapped array. I need a way that all the rendered buttons will get their respective links. My code is below, I am using react ModalVideo to show my YouTube video.
<ul className="list-unstyled">
{datalist.lectures.map((value, index) => {
return (
<li key={index}>
<ModalVideo channel='youtube' autoplay isOpen={isOpen} videoId={value} onClose={() => setOpen(false)} />
<button className="play-icon" onClick={()=> setOpen(true)}> <i className="las la-play"></i> Lecture: {index+1}</button>
</li>
)})}
</ul>
All the links are coming from Json file where the code looks like this
"lectures": [
"BT4YihNXiYw",
"NSFLhnv2pQI",
"sEPxqpFZit8",
"fU8QhoUJ_sE",
"r3XFYOtvUng",
"MZAkMddxhpg"
]
I think the problem I have right now is that after the page render and mapping ends it only remembers what the last link is store in value, because of that no matter which button i click it shows me the last value of the mapped array
Just some quick ideas looking at the minimal snippets available.
let's not to render multiple ModalVideo component like above, move it out from the map.
Use another state to keep track the change of the youtube videos' ID.
For example
const [isOpen, setOpen] = useState(false);
const [videoId, setVideoId] = useState(null);
const playVideo = (vid) => {
setOpen(true);
setVideoId(vid);
};
return (
<div>
<ModalVideo
channel='youtube'
autoplay
isOpen={isOpen}
videoId={videoId}
onClose={() => setOpen(false)}
/>
<ul className="list-unstyled">
{
datalist.lectures.map((value, index) => {
return (
<li key={index}>
<button className="play-icon" onClick={() => playVideo(value)}>
<i className="las la-play"></i>
Lecture: {index + 1}
</button>
</li>
)
})
}
</ul>
</div>
);
I am working with an angular 6 application, in the HTML template I have some code as per below, just showing the table cell part of the array, also the table is built using divs.
<div class='table_small'>
<div class='table_cell'>Status</div>
<div class='table_cell'>
<p class="status" >{{incomingData.status}}</p>
</div>
</div>
Please note here that "data" is an array (*ngFor) and is being used in row data and there are multiple data in the table.
Now I have a situation wherein there is a button inside the table rows to cancel the particular order, when the user clicks in, a pop up/modal asks for user confirmation, if the user opts for 'Yes' it would change the status field value to "cancellation is in process" temporarily before it hits the service, once there is a successful response from the customer it would change the station to "cancelled".
I am really not sure how to do the cancellation within the table cell here, if anyone can give insight on this please do.
Thanks
You could pass the element to the function and edit its status:
<div class='table_small'>
<div class='table_cell'>Status</div>
<div class='table_cell'>
<p class="status" >{{incomingData.status}}</p>
</div>
<div class='table_cell'>
<button (click)="showCancelModal(incomingData)"> Cancel</p>
</div>
</div>
And then in the component something like this:
showCancelModal(incomingData) {
// logic for showing modal and retrieving user response
if( response === 'yes') {
incomingData.status = 'Cancel in progress';
yourService.cancel(incomingData)
.pipe( finally(() => incomingData.status = 'Cancelled') )
.subscribe();
}
}
I have created a sidebar nav menu in angular 2 something like shown in the pic below.
https://imgur.com/a/hj4zO
UPDATE:
But when i click on the link in the category list, i get all the products relevant to clicked category. But it is not displaying to the right in the dashboard.
My logic to display the products is in another component: dashboard.component.html
<div id="products" class="row list-group">
...
</div>
But on click of an item in sidebar (from sidebar component), i m not sure where to put the above div, so i get all the products filtered based on the click to my dashboard area.
Basically when i onclick getProducts (from one component: sidebar, the function from another component : dashboard should be called)
sidenav.component.html
<md-sidenav-container fullscreen>
<md-sidenav #sidenav mode="side" class="example-sidenav" [ngStyle]="{ 'width.em': sidenavWidth }" opened="true" (mouseover)="increase()"
(mouseleave)="decrease()">
<md-nav-list>
<md-list-item routerLinkActive="active">
<md-icon md-list-icon>room_service</md-icon>
<div fxFlex="10"></div>
<div *ngIf="sidenavWidth > 6" class="sidenav-item">
<p class="lead">Smiles 4 abc </p>
<div class="catList" id="catList">
<a *ngFor="let cat of categories; let i = index" href="javascript:; " class="list-group-item " (click)="getProducts(cat._id,i)">{{cat.category_name}}</a>
</div>
</div>
</md-list-item>
</md-nav-list>
</md-sidenav>
<div class="example-sidenav-content">
<router-outlet></router-outlet>
</div>
</md-sidenav-container>
sidenav.component.ts
ngOnInit() {
this.qty[1]=1;
this.catService.getMaincategories('Yes').subscribe(
(mainCategories) => {
this.categories = mainCategories.mainCategories
let firstCatId = this.categories[0]._id;
this.getProducts(firstCatId,0)
}
);
this.navbar.ngOnInit();
}
getProducts(category_id, i) {
console.log('prod clicked..');
this.productService.getProductsOncategory(category_id).subscribe(
(products) => {
this.products = products.products
}
);
}
product.service.ts
getProductsOncategory(category_id){
let catUrl=this.domain+"products/getProductsOncategory"
let headers = new Headers();
headers.append('Content-Type','application/json');
let catIdObj = JSON.stringify({category_id:category_id,product_status:'Yes'})
return this.http.post(catUrl,catIdObj,{headers:headers})
.map((response:Response)=>response.json())
.catch(this.handleError);
}
app.component.html
<sidenav></sidenav>
Logic is very simple in Angular for dealing these type of problem. Follow following steps:
Create a Subject in your service:
public products$ = Subject<{}>(); // use model instead of {}
In your sidenav component inject service and emit product data.
this.service.products$.next(data)
In your dashboard component subscribe to subject.
this.service.products$.subscribe(data => { console.log(data)});
Hope it will help.
My cordova ionic 1 code currently load all the rss feeds and this cause my page is too long due to too many rss feeds.
Thus, I just want to display the first three rss item at preset(which is in collapse state). When click on 'More',it will expand and display all items. Click again, it will collapse and show only the first rss.
Currently, no rss items shows in collapse state. It shows all in expandable state.
What I required:
Display first three rss items, sort with date(latest on top) in collapse state.
Display all rss items when it is expandable state.
my template
<div class="card">
<div class="item item-divider">RSS</div>
<a class="item item-icon-right" ng-if='showmore' ng-repeat="item in rssNews| orderBy: 'pubDate':true" ng-click="openitems(item.link)">
<h2>{{item.title}}</h2>
<h6>{{item.pubDate}}</h6>
<p {{story.description | htmlToPlaintext}}</p>
</div>
</a>
<div ng-click="togglemore()" <i class="icon" ng-class="showmore ? 'ion-android-remove-circle assertive' : 'ion-android-add-circle positive'"></i><span class="padding" ng-bind="showmore ? 'Less' : 'More'"></span></div>
</div>
angularjs
$scope.showmore = false;
$scope.togglemore = function() {
$scope.showmore = !$scope.showmore;
};
collapse condition .Initial state.(Look at the '+' sign in blue color). None of the rss was shown. I want first 3 rss feeds to display.
Expand condition. It will show all the rss feeds.
Example, the rss feeds link is as below
https://www.google.com/finance/company_news?q=KLSE:AEON&ei=pKh8WfndJ9G8uQTKgKq4CQ&output=rss
another JS
$webServicesFactory.get(
"https://www.google.com/finance/company_news",
{},
{
output: "rss",
q: 'KLSE' + ":" + 'AEON'
}
).then(
function success(xmlData) {
var x2js = new X2JS();
$globalFactory.personalStockNews = x2js.xml_str2json(xmlData).rss.channel.item;
console.info($globalFactory.personalStockNews);
$state.go("app.page");
},
function error(error) {
$globalFactory.personalStockNews = null;
$ionicLoading.hide();
$state.go("app.page");
}
);
},
function error(error) {
$ionicLoading.hide();
}
);
$scope.rssNews = $globalFactory.personalStockNews;
In case you are confused with what is collapse and expand, this is the example.
http://jsfiddle.net/shengoo/6b0y3tar/
Here's a demo: http://jsfiddle.net/afagx45b/1/
I used the | limit to x filter of ng-repeat along with a simple ng-if statement on the div to know if show-more or show-less have been clicked. You should be able to adapt the rest to your needs.
When show-less is visible:
<div ng-if="showmore" ng-repeat="group in groups | orderBy: 'date'">
and show-more is visible:
<div ng-if="!showmore" ng-repeat="group in groups | orderBy: 'date' | limitTo:3">
Edit: Updated to show how to order by a date, check out this thread for more info on the orderBy filter.
Angular comes with a limitTo:limit filter, it support limiting first x items and last x items:
<a class="item item-icon-right" ng-if='showmore' ng-repeat="item in rssNews| limitTo:1 | orderBy: 'pubDate':true" ng-click="openitems(item.link)">
you can find more info in the documentation
You can use limitTo as suggested by #marco gomes. You can set a variable to 3 initially which will tell ng-repeat to show only 3 rss items by default. But when you toggle to view more, then we will set the variable to length of the array to show all rss items.
HTML:
<div class="card">
<div class="item item-divider">RSS</div>
<a class="item item-icon-right" ng-if='showmore' ng-repeat="item in rssNews| limitTo:count | orderBy: 'pubDate':true" ng-click="openitems(item.link)">
<h2>{{item.title}}</h2>
<h6>{{item.pubDate}}</h6>
<p> {{story.description | htmlToPlaintext}}</p>
</div>
</a>
<div ng-click="togglemore()"> <i class="icon" ng-class="{'showmore' ? 'ion-android-remove-circle assertive' : 'ion-android-add-circle positive'}"></i><span class="padding" ng-bind="showmore ? 'Less' : 'More'"></span></div>
</div>
JS:
$scope.count=3;
$scope.showmore = false;
$scope.togglemore = function(){
$scope.showmore = !$scope.showmore;
if($scope.showmore)
$scope.count=$scope.rssNews.length;
else
$scope.count=3;
};
Working Example: http://jsfiddle.net/6b0y3tar/190/
I've done filtering numerous times before, but am having trouble with this specific case. I have a list of objects set up in pagination, but I also want to be able to filter them for ease of use. An example object might look like:
{
baseline:0.75
clonedFrom:Object
description:"Just a simple description.."
includeable:false
key:"bc889881-7979-4e04-b586-d53faab26b6b"
name:"Just a simple question?"
type:"BayesianModel"
version:1483477351992
versionComment:null
versionLabel:"0.11"
}
For the most part, what the object looks like is arbitrary, I just included it for ease of answering. I am trying to filter on both the name and description of the object at the same time. For example if the user knew a key word in either they could narrow down the results.
I have the input for the filter and the results inside of a <ul> shown below:
<ul class="list-group">
<li class="list-group-item">
<div class="form-group has-feedback">
<input type="text"
ng-model="vm.resultFilter"
ng-change="vm.updateFilter()"
class="form-control filterInput"
placeholder="Filter Results" />
<span ng-if="vm.resultFilter"
ng-click="vm.resultFilter = ''; vm.updateFilter();"
class="fa fa-times fa-lg form-control-feedback">
</span>
</div>
</li>
<li class="list-group-item link-row model-list"
ng-repeat="result in vm.filteredResults
| startFrom : ((vm.currentPage - 1) * vm.itemsPerPage)
| limitTo: vm.itemsPerPage"
ng-if="result.name != vm.model.name"
ng-click="vm.selected = result;"
ng-class="{selected: result === vm.selected}"
ng-init="displayNumber = vm.incrementDisplayIndex();">
<h4 class="list-group-item-heading">{{result.description}} - {{result.name !== vm.model.name}}</h4>
<p class="list-group-item-text">
{{result.name}}
</p>
</li>
</ul>
So the name of the filter is vm.resultFilter and the cooresponding method that is called every time the filter is updated is updateFilter() (which is necessary for the pagination stuff).
function updateFilter() {
vm.filteredResults = $filter('filter')(vm.results, {
'name': vm.resultFilter,
'description': vm.resultFilter
});
vm.totalItems = vm.filteredResults.length;
vm.noOfPages = Math.ceil(vm.filteredResults.length / vm.itemsPerPage);
}
I am just having trouble with getting the filtering to work 100%. Sometimes it appears it's only filtering on the description field, but then sometimes I will search a word that is in the description field of only one result and it will filter with no results (which would be false). Any tips appreciated.
Since your are not using the filter inside your HTML, I recommend you to use the filter property from the Array prototype.
function updateFilter() {
vm.filteredResults = vm.results.filter(function(item){
return (item.name==vm.resultFilter || item.description==vm.resultFilter )
}
vm.totalItems = vm.filteredResults.length;
vm.noOfPages = Math.ceil(vm.filteredResults.length / vm.itemsPerPage);
}
In case you need to determines whether a string contains the characters of a specified string. You might need to use includes instead of ==
vm.filteredResults = vm.results.filter(function(item){
return (item.name.includes(vm.resultFilter) || item.description.includes(vm.resultFilter) )
}