B4J Tutorial [BANano] - Creating a News Website / WebApp in less than 100 lines of code

Ola

Download

First get yourself an API from NewsApi, this is free for non-commercial apps,
mainapp.png


The API provides one with latest top news in batches of 10 items at a time and also sources of those news..

topnews.png


For this I could have used BANanoFetch, you can too, but I wanted to test my BANanoPHP lib in getting json files from the net, so I ran this.

B4X:
Dim fKey As String = $"https://newsapi.org/v2/top-headlines?sources=techcrunch&apiKey=${apiKey}"$
    ' we will use php getjson
    Dim bPHP As BANanoPHP
    bPHP.Initialize
    Dim articlesJSON As String = BANano.CallInlinePHPWait(bPHP.FILE_GETJSON, bPHP.BuildFileGetJSON(fKey))
    Dim articlesMAP As Map = BANano.FromJson(articlesJSON)
    Dim items As List = MyApp.newlist
    Dim articles As List = articlesMAP.getdefault("articles", items)

We convert this to a simple card.

newsapp.png



Next we need a way to loop though each article and then display it in our page. With the abstract designer, this is rather easy. We design out card outline.
Each card with an article will be rendered inside an RC (i.e. row column). Each column should span 8 spaces. We place various elements into our stage depending on where stuff should be..

bvmad.png


Of course the social media buttons are just for show. We have a chip, a spacer, some buttons with icons inside and then a spacer and another button.

In the definition of the "Read More" button, we bind its HREF to the article url.

readmore.png


So when one clicks the URL, it will open up the page that has that news article.

We needed a way to list all the top articles via a loop. As earlier indicated, the card definition sits on an RC, this RC is inside the div. We need to tell our app that we will create a new card for each new article we have. In VueJS this is rather easy with a v-for directive,

housingdiv.png


See the Key and VFor properties in the bag for the div.
 
Last edited:

Mashiane

Expert
Licensed User
Longtime User
Just like the href and the key properties above, each screen element that we want to show content from our articles source, we just specify the binding.

We need to have a housing frame for our app, so we create the master skeleton and load this via code.

B4X:
Sub Init
    'load the mainlayout we will use
    BANano.LoadLayout("body", "applayout")
    'initialize the vue instance, we will render it to #app div element
    MyApp.Initialize(Me, "app", "body")
    'load the newsarticle layout
    BANano.loadlayout("#pgcontainer", "newsarticles")
    'load the newssource layout with list
    BANano.loadlayout("#navdrawer", "newssource")
   
    BindComponents
    'show the drawer when the app opens
    navdrawer.Show
    'keep errors and sources for the news
    MyApp.SetData("articles", MyApp.NewList)
    MyApp.SetData("errors", MyApp.NewList)
    MyApp.SetData("sources", MyApp.NewList)
    'get the news when the app is created
    MyApp.SetCreated(Me, "GetNewsAndSources")
    'register the method to get avatars
    MyApp.SetMethod(Me, "getimgurl")
    'serve the webapp
    MyApp.Serve   
End Sub

This is indicated above... We drag our navbar, drawer, footer, main container to our abstract designer. We place these where we would like to see them. BANano does the rest.

skeleton.png


As noted on the code, the first layout to load is 1. applayout and then we load the newsarticle layout. The 3rd layout we need to load is the one for the drawer items where the news sources will be listed so that we can choose and source and view its articles..
 
Last edited:

Mashiane

Expert
Licensed User
Longtime User
Next is the nav bar drawer, we need it to list all sources of the news. We need to place a list inside the drawer. We fire up our abstract designer and design the view outline,

Each key for each item on the list will be sourced from :source.id and each title sources from {{ source.name }}

We also need a way to get the source images. To do this, we will bind the src attribute to a callback, :getimgurl(source.id)

This will receive the source id and then create a path for the image to display. We define the callback as:

B4X:
'sub to get images
Sub getimgurl(url As String) As String
    'build img path
    Dim strURL As String = $"./assets/${url}.png"$
    Return strURL
End Sub

You might be wondering, why these are one below another for the image and title. It doesnt matter because they are inside a parent of their own, think of sequence, its the image first then the title. In simple terms, its <div><image></image><title></title></div>

sourceitem.png


For each item in the sources JSON we got from the API, will render.

drawerx.png


Now we need to detect click events for each nav drawer item and just show those news...
 

Mashiane

Expert
Licensed User
Longtime User
So for each item in the drawer, we loop through each "source" from the sources list we created from the API.

1592605881625.png


The key helps here as we bind it to each source.id, meaning that when we click each list item in the drawer, the item returned is the id.

B4X:
'when each news source is clicked, update the articles
Sub newssource_click (argument As Object)
    SetSource(argument)
End Sub

So what we need to do now is that each time a source is clicked, we need to get the "articles" for that source. As soon as we do that our articles listing will change automatically as the "articles" state has been changed.

This fires:

B4X:
'fire when a source is changed
Sub SetSource(sSource As String)
    'get the top headlines
    Dim sKey As String = $"https://newsapi.org/v2/top-headlines?sources=${sSource}&apiKey=${apiKey}"$
    ' we will use php getjson
    bPHP.Initialize
    Dim articlesJSON As String = BANano.CallInlinePHPWait(bPHP.FILE_GETJSON, bPHP.BuildFileGetJSON(sKey))
    Dim articlesMAP As Map = BANano.FromJson(articlesJSON)
    Dim items As List = MyApp.newlist
    Dim articles As List = articlesMAP.getdefault("articles", items)
    MyApp.SetData("articles", articles)
End Sub

Summary:

1. When our app starts, a list of news articles (latest articles) from TechCrunch are displayed using the News API.
2. We then load all sources of the news that we can get from the news API and these are displayed in the drawer.
3. When we click each source, the news articles are changed.
4. You can click on Read More to get more details about that article.

Enjoy

Supporting libraries to be made available soon.
 
Last edited:

Mashiane

Expert
Licensed User
Longtime User
Complete source code

B4X:
'Static code module
Sub Process_Globals
    Private BANano As BANano
    Private MyApp As VueApp
    Private navdrawer As VNavigationDrawer
    Private navmenu As VAppBarNavIcon
    Private apiKey As String = "XXXXXXX"
    Private newssource As VListItem
    Private bPHP As BANanoPHP
End Sub

Sub Init
    'load the mainlayout we will use
    BANano.LoadLayout("body", "applayout")
    'initialize the vue instance, we will render it to #app div element
    MyApp.Initialize(Me, "app", "body")
    'load the newsarticle layout
    BANano.loadlayout("#pgcontainer", "newsarticles")
    'load the newssource layout with list
    BANano.loadlayout("#navdrawer", "newssource")
    'show the drawer when the app opens
    navdrawer.Show
    'keep errors and sources for the news
    MyApp.SetData("articles", MyApp.NewList)
    MyApp.SetData("errors", MyApp.NewList)
    MyApp.SetData("sources", MyApp.NewList)
    'get the news when the app is created
    MyApp.SetCreated(Me, "GetNewsAndSources")
    'register the method to get avatars
    MyApp.SetMethod(Me, "getimgurl")
    'bind component states and events
    BindComponents
    'serve the webapp
    MyApp.Serve  
End Sub

'toggle the drawer
Sub navmenu_clickstop (event As BANanoEvent)
    navdrawer.toggle
End Sub

'get news from api
Sub GetNewsAndSources
    'get the top headlines
    Dim fKey As String = $"https://newsapi.org/v2/top-headlines?sources=techcrunch&apiKey=${apiKey}"$
    ' we will use php getjson
    Dim bPHP As BANanoPHP
    bPHP.Initialize
    Dim articlesJSON As String = BANano.CallInlinePHPWait(bPHP.FILE_GETJSON, bPHP.BuildFileGetJSON(fKey))
    Dim articlesMAP As Map = BANano.FromJson(articlesJSON)
    Dim items As List = MyApp.newlist
    Dim articles As List = articlesMAP.getdefault("articles", items)
    MyApp.SetData("articles", articles)
    'get the sources
    Dim sKey As String = $"https://newsapi.org/v2/sources?language=en&apiKey=${apiKey}"$
    Dim sourcesJSON As String = BANano.CallInlinePHPWait(bPHP.FILE_GETJSON, bPHP.BuildFileGetJSON(sKey))
    Dim sourcesMAP As Map = BANano.FromJson(sourcesJSON)
    Dim sourcesl As List = MyApp.newlist
    Dim sources As List = sourcesMAP.getdefault("sources", sourcesl)
    MyApp.SetData("sources", sources)
End Sub

'fire when a source is changed
Sub SetSource(sSource As String)
    'get the top headlines
    Dim sKey As String = $"https://newsapi.org/v2/top-headlines?sources=${sSource}&apiKey=${apiKey}"$
    ' we will use php getjson
    bPHP.Initialize
    Dim articlesJSON As String = BANano.CallInlinePHPWait(bPHP.FILE_GETJSON, bPHP.BuildFileGetJSON(sKey))
    Dim articlesMAP As Map = BANano.FromJson(articlesJSON)
    Dim items As List = MyApp.newlist
    Dim articles As List = articlesMAP.getdefault("articles", items)
    MyApp.SetData("articles", articles)
End Sub

'sub to get images for the drawer
Sub getimgurl(url As String) As String
    'build img path
    Dim strURL As String = $"./assets/${url}.png"$
    Return strURL
End Sub

'IMPORTANT: bind component states and events
Sub BindComponents
    'bind state and events for navdrawer
    navdrawer.AddToApp(MyApp)
    'bind state and events for navmenu
    navmenu.AddToApp(MyApp)
    'bind the list item
    newssource.AddToApp(MyApp)
End Sub

'when each news source is clicked, update the articles
Sub newssource_click (argument As Object)
    SetSource(argument)
End Sub
 

Mashiane

Expert
Licensed User
Longtime User
if you can upload complete project.
The source code for this project is under the 3. WebApps folder. Please note that due to the library still being under development (in beta), its not recommended to use it for production. I am testing its full potential with the webapps, thus the release of this pre-release. Please understand.

Here we go: https://github.com/Mashiane/BANanoVuetifyAD
 
Top