Ionic 5 Directory tree dynamically - ionic-framework

I have done a simple JavaScript file browser which shows the contents of each directory, loading the subdirectory contents from the backend using an AJAX request when the directory name is clicked. Loading the full tree is out of the question. The directory contents are sent in JSON. The directory is something like the one below and cannot be loaded as a whole recursively due to the number of directories and files. The (imaginary) directory structure is simple, but it can have several nested levels:
docs
assemblies
2019-07
doc-6811.txt
instructions-6811.pdf
2019-08
doc-7012.txt
instructions-7012.pdf
...
invoices
2019-07
invoice-6811.pdf
2019-0
invoice-7012.pdf
tickets
2019-07
ticket-98141.txt
The items for each directory are in an array of JS Objects:
[{
name: '2019-07',
isDirectory: true,
fullPath: "/mnt/samba/docs/assemblies/2019-07"
},
{
name: '2019-08',
isDirectory: true,
fullPath: "/mnt/samba/docs/assemblies/2019-08"
} ...
]
There are files as well, of course, but they are not a problem. Now I need to do the same in Ionic but, I am totally lost with the starting point. The top directory renders nicely and the current simple template (I call it a template) is something like this:
<ion-content>
<ion-list>
<ion-item-sliding *ngFor="let d of directories">
<ion-item (click)="openFolder(d)"> <!-- just an example call --->
<ion-icon name="folder" slot="start" *ngIf="d.isdirectory"></ion-icon>
<ion-icon name="triangle" slot="start" *ngIf="!d.isdirectory"></ion-icon>
<ion-label text-wrap>
{{ d.name }}
<p>{{ d.fullPath }}</p>
</ion-label>
<!-- THIS is where the directory contents should appear using
the same structure as this template -->
</ion-item>
</ion-item-sliding>
</ion-list>
</ion-content>
What the code should do is simply fetch the data from the backend and bind it to an array variable, which would then be rendered below to the spot given above. Can this be done in Angular, or is using some other framework any easier? I assume there is a component approach of some sort available, but it should be totally dynamic and fetching plus rendering of one directory should take place per request.
Fetching the directories is a simple task and I get the array just fine. However, I have not been able to get any rendering done yet. Any alternatives and/or pointers are welcome.

Your JSON has to be a recursive JSON. By that I mean,
{ "items": [
{
"name": "ABC1",
"isDirectory": true,
"fullPath": "/mnt/samba/docs/assemblies/2019-07",
"children":[
{
"name": "ABC11",
"isDirectory": true,
"fullPath": "/mnt/samba/docs/assemblies/2019-08"
},
{
"name": "ABC12",
"isDirectory": true,
"fullPath": "/mnt/samba/docs/assemblies/2019-08"
}
]
},
{
"name": "ABC2",
"isDirectory": true,
"fullPath": "/mnt/samba/docs/assemblies/2019-08"
}
]
}
If it can be this way, you can handle the same using recursive ng-template
A sample of the same is as given in this link.
Click here to view the link.
A little Google on recursive ng-template can also help. :)
I sincerely hope that this helps.

Related

Search results link tabs

I'm building a search application and am trying to get some results links that appear in tab format to work. Much like you see on google.com/search=?user_query and bing.com/search=?user_query... where after you submit the initial query, you can click on "Images", "Shopping" and "News" for example and a different results view is rendered based on the the result link/tab that you clicked.
I'm using ReactiveSearch to build my search UI. So far I have this:
ResultNavigationTabs.tsx to build the link tabs
class ResultNavigationTabs extends Component {
render() {
const { classes, items, location: { pathname } } = this.props;
return (
<ul className={classes.nav}>
{items.map(item => (
<Link to={item.link} key={item.text}>
<li className={item.link.startsWith(pathname) ? "active" : ""}>
{item.text}
</li>
</Link>
))}
</ul>
);
}
}
export default withStyles(styles)(withRouter(ResultNavigationTabs));
I then render this component in my ResultsViewPage.tsx like so:
render() {
const { selected } = this.state;
...(omitted for brevity)
<ResultNavigationTabs2
className={classes.myNavigationTabs}
items={[
{ text: "Web", link: `/search?q="${selected}"` },
{ text: "News", link: `/news?q="${selected}"` },
{ text: "Shopping", link: `/shopping?q="${selected}"` },
]}
/>
The links do render but they do not work. If I hover over the links, the search query string is empty (http://localhost:3000/search?q=%22%22). If you've worked with ReactiveSearch, it should be: http://localhost:3000/search?q=%22user%20query%22.
I have had it working but only when I render ResultNavigationTabs in the same file as the search box (DataSearch in ReactiveSearch language). However, if I do that it appears right below the search box in the Header instead of the results area.
I need to figure out a way to render ResultNavigationTabs in the ResultsViewPage.tsx file with working links.
After doing some more thoughtful searching, I found the answer right here on SO! Comes complete with 2 CodeSandBox demos as well - check them out.

How to display image from mongodb using Reactjs

I've saved my image in Mongodb like that :
"img": {
"data": "<Binary Data>",
"contentType": "image/png"
}
I try to display it in ReactJS using this code :
..{products.map(product => {
<img src= {product.img} />
But nothing is displayed. Any idea please to fix it.
You are trying to display your image in src attribute with binary data when it expect an url.
If it's binary data you need to diplay it like this and tell to your component that you are passing binary data
<img src={`data:image/png;base64,${product.img.data}`} />

How to search based on Rest API data?

I've created Rest API, connected to Ionic app successfully and displayed data.
home.html
<ion-content padding>
<ion-card *ngFor="let item of allProducts">
{{item.title}}
</ion-card>
</ion-content>
home.ts
ionViewWillEnter(){
this.productProvider.getProduct()
.subscribe(productList=> this.allProducts=productList);
}
API has example data like below, product titles like below:
abc
xyz
rmn
zxy
My question is:
In search bar, if I give abc and then enter, it should display that particular product.
How can I do this? I tried <ion-searchbar> but it is not working.
Could any one tell me how to do this? Or is there any tutorial for my case?
<ion-searchbar (ionInput)="getItems($event)"></ion-searchbar>
getItems(event) {
let search = event.target.value;
if (search && search.trim() != '') {
this.productProvider.getProduct(search).subscribe((products) => {
console.dir(products);
}, (err) => {
console.log(err);
});
}
}
You can use ionInput event to send search based api request

Could not check the data in array of array

I need to check that my app has the data that i give in my array
i have a html like this
<ion-card class="card1">
{{name}}
</ion-card>
<ion-card class="card2" *ngfor="prod of orderlist>
{{products}}
</ion-card>
In my e2e
describe('module',()=>{
it('should have the same data in list array'),() => {
var quantity = element(by.css('.card2');
expect(quantity.getText()).toContain(list[0].product[0].check)
});
//my array
var list = [{ name : 'yoke',
product :[{check :'no' },
{check :'no' }]
}];
});
what i need is that my app has a field with a value "no", I need to check it weather that data is present in my card, in the same way i have a big sized array
while testing this in protractor it says that "Cannot find name 'product'. (2304)"

Polymer REST backend

I have a backend written in golang exposing /api/list interface. It returns lists when called from GET and create new list when it receive POST with parameters.
I can read it with standard core-ajax element, there is a huge amount of examples to do that.
What I didn't understood is what should I do, when I want to create new element through POST? I read the documentation and searched for sample code for half day, can you point me to right direction?
//
Ok, thanks for help, it was really only bad format of json I was sending. There is still dark cloud in my mind telling that I misunderstood something from conceptual view. Is this:
<link rel="import" href="bower_components/polymer/polymer.html">
<link rel="import" href="bower_components/core-ajax/core-ajax.html">
<polymer-element name="channels-service" attributes="channels">
<template>
<style>
:host {
display: none;
}
</style>
<core-ajax id="ch_load"
auto
url="/api/list"
on-core-response="{{channelsLoaded}}"
handleAs="json">
</core-ajax>
<core-ajax id="ch_update"
url="/api/list"
on-core-response="{{channelsUpdated}}"
method="POST"
handleAs="json">
</core-ajax>
</template>
<script>
Polymer('channels-service', {
created: function() {
this.channels = [];
},
channelsLoaded: function() {
// Make a copy of the loaded data
this.channels = this.$.ch_load.response.slice(0);
},
newChannel: function(ch_name) {
// this.$.ch_update.body = "ch_name";
this.$.ch_update.body = '{"Name":"pitchalist2"}'
this.$.ch_update.go();
},
channelsUpdated: function() {
//window.log(this.$.ch_update.response.slice(0));
}
});
</script>
</polymer-element>
correctly written data layer? It looks very counterintuitive to me and in examples using local data storage it works way easier.
You can send a POST request by setting the method attribute (method="POST") and the body attribute (body='{"my":"data"}'). Indeed you need a second iron-ajax element for this request.
See the attributes section in the iron-ajax documentation.