I recently had a question if it was possible to create a Facebook-like WebApp with ABMaterial for B4J. I had some time to spare tonight (yeah right) and decided to give it a go…
All I needed were a couple of ABMContainers and the new CloseContent/OpenContent feature introduced in 3.02. The existing NextContent system would provide the infinite page.
It also uses a ABMCustomComponent for the ‘Like’ feature (I based it on this project), and you can find the source code of the class under the video:
About an hour, and 200 lines of B4J code later, I had a working timeline! A real project would of course need some way to add an article, save them in the database, user management, etc but this is out of scope of this article.
Note: This example will be included in the upcoming 3.02 Maintenance Update, but I would like to share the source source code for the ‘Like’ functionality beforehand.
Source code for the ‘Like’ custom component.
You’ll need this zip file for the images and js/css files. Put the images and css in the /www/css/custom folder, the js file in the /www/js/custom/ folder.
The class LikeComponent:
'Class module Sub Class_Globals Public ABMComp As ABMCustomComponent Public Counter As Int End Sub 'Initializes the object. Countries and data are Json Strings Public Sub Initialize(InternalPage As ABMPage, ID As String, AlreadyLiked As Int) ABMComp.Initialize("ABMComp", Me, InternalPage, ID) Counter = AlreadyLiked End Sub Sub ABMComp_Build(internalID As String) As String Return $" <div id="${internalID} class="facebook-reaction"><!-- container div for reaction system --> <span class="like-btn"> <!-- Default like button --> <span class="like-btn-emo like-btn-default"></span> <!-- Default like button emotion--> <span class="like-btn-text">Like</span> <!-- Default like button text,(Like, wow, sad..) default:Like --> <ul class="reactions-box"> <!-- Reaction buttons container--> <li class="reaction reaction-like" data-reaction="Like"></li> <li class="reaction reaction-love" data-reaction="Love"></li> <li class="reaction reaction-haha" data-reaction="HaHa"></li> <li class="reaction reaction-wow" data-reaction="Wow"></li> <li class="reaction reaction-sad" data-reaction="Sad"></li> <li class="reaction reaction-angry" data-reaction="Angry"></li> </ul> </span> <div class="like-stat"> <!-- Like statistic container--> <span class="like-emo"> <!-- like emotions container --> <span class="like-btn-like"></span> <!-- given emotions like, wow, sad (default:Like) --> </span> <span class="like-details">${Counter} others</span></div> </div> "$ End Sub Sub ABMComp_FirstRun(InternalPage As ABMPage, internalID As String) Dim script As String = $"$("#${internalID} .reaction").on("click",function(){ // like click var data_reaction = $(this).attr("data-reaction"); $("#${internalID} .like-details").html("You and ${Counter} others"); $("#${internalID} .like-btn-emo").removeClass().addClass('like-btn-emo').addClass('like-btn-'+data_reaction.toLowerCase()); $("#${internalID} .like-btn-text").text(data_reaction).removeClass().addClass('like-btn-text').addClass('like-btn-text-'+data_reaction.toLowerCase()).addClass("active");; if(data_reaction == "Like") { $("#${internalID} .like-emo").html('<span class="like-btn-like"></span>'); } else { $("#${internalID} .like-emo").html('<span class="like-btn-like"></span><span class="like-btn-'+data_reaction.toLowerCase()+'"></span>'); } var json = {'target': '${internalID}', 'like': data_reaction}; b4j_raiseEvent('likecomponent_liked', json); }); $("#${internalID} .like-btn-text").on("click",function(){ // undo like click if($(this).hasClass("active")){ $("#${internalID} .like-btn-text").text("Like").removeClass().addClass('like-btn-text'); $("#${internalID} .like-btn-emo").removeClass().addClass('like-btn-emo').addClass("like-btn-default"); $("#${internalID} .like-emo").html('<span class="like-btn-like"></span>'); $("#${internalID} .like-details").html("${Counter} others"); var json = {'target':'${internalID}'}; b4j_raiseEvent('likecomponent_unliked', json); } })"$ InternalPage.ws.Eval(script, Array As Object(ABMComp.ID)) ' flush not needed, it's done in the refresh method in the lib End Sub Sub ABMComp_Refresh(InternalPage As ABMPage, internalID As String) End Sub ' do the stuff needed when the object is removed Sub ABMComp_CleanUp(InternalPage As ABMPage, internalID As String) End Sub
Usage:
Sub Class_Globals ... Dim myLike As LikeComponent ... End Sub ' adding the component myLike.initialize(page, ID & "Like", Rnd(20, 500)) myContainer.Cell(4,1).AddComponent(myLike.ABMComp)
Events (the name LikeComponent is set in the FirstRun() method of the class:
public Sub LikeComponent_Liked(value As Map) Log(value.Get("like") & " ----> " & value.Get("target")) End Sub public Sub LikeComponent_UnLiked(value As Map) Log("Unliked ----> " & value.Get("target")) End Sub
Et voila, a nice little demonstration of what you can make using B4J and ABMaterial.
I’ll end with a little word of advice:
If you only plan to learn one programming language this year, B4X is definitely the one you should pick! With ABMaterial, I give you the power to write responsive, professional WebApps, and with the other B4X tools you write native Android, iOS, Desktop (Mac, Windows, Linux), Raspberry Pi and Arduino apps. All with the same language! You’ll wonder why you ever bothered looking at all those other pricy programming tools out there…
Happy programming!
Alwaysbusy