Free Artificial Intelligence Course

As a front-end developer, I happen to hear these terms quite often: Deep learning, machine learning, neuroscience, … However, I did not have any knowledge nor considerable experience in these fields. Also, when you don’t know something, it scares you even more, because fear leads to the dark side.

Many developers have the fear of replacement in the future. We fear that artificial intelligence may suddenly cast us out. This is certainly because of the ignorant and lazy man inside of us all. Therefore, I decided to thinner this grumpy man’s voice in me and followed the artificial intelligence course created by University of Helsinki and reaktor.com.

Course Content

Elements of AI will introduce you common AI patterns, terminology, problem solving techniques and many other theoretical topics that you should cover. Their curriculum is well organised and comprehensive. All in all, this beginner course helps you build fundamental knowledge to start your AI development career. On the other hand, the creators of the course aimed to target a broad range of individuals. Therefore, it is not specifically tailored for programmers or other IT roles. So, you don’t have to have programming skills. However, if you are already an IT professional, this is a big plus to comprehend the discussions.

Here is a list of my favourite topics throughout the course:

  • How to define AI?
  • AI for board games like tic-tac-toe, go, chess.
  • Why we should use different methods to solve different problems?
  • How can we reach for General AI?
  • AI Winter
  • The Bayes Rule
  • The types of machine learning
  • Neural networks

Exercise Tips

You will be asked to complete some exercises on almost every section. Most of them are tests that can be answered with some radio buttons. However, I recommend you to be careful while answering the questions. Not all of them are easy to answer and there are some tricky questions. So, think twice before pressing the submit button. I got 85% success rate, but it would be higher if I were more careful and patient before making my mind about the answers.

The course also provides some open-ended questions. Elements of AI created a smart solution to review the answers. They use the other students’ judgment to score one another. For example, after you write your answer (several paragraphs) for an open-ended questions, you are required to review 3 other students’ answers for the same question. So that, the community builds a fair and reliable control mechanism for itself.

After the course completion, you will receive a free digital certificate approved by University of Helsinki. Of course, the certificate is just a make up. What you have learnt and what you will do with gained knowledge is way more significant than a piece of paper. However, this certificate might have academic value for university students. Elements of AI grants you 2 ECTS credits. According to the info on their website, these credits are only valid in Finland, but you may try to convince your faculty in another EU country. Just try.

What’s next?

I have been informed by Elements of AI, thanks to the continuous growth environment of Fremtind AS. My colleague Berit Klundseter dropped an introductory post about this course via Fremtind’s social network. Then, I talked to our Senior Machine Learning Engineer Emanuele Lapponi and he recommended another course where I could program some practical cases. So, my AI journey continues with the support of my colleagues.

I hope this post made you curious about AI topic and if you also have dedication to finish the course, may the force be with you! 🙂

Sercan Leylek

How to mock addEventListener in React Testing Library?

This question puzzled my mind for some time and I noticed that there is no good post which provides an up-to-date answer to the challenge. Basically, this article will help you solve your testing problem in React and I also provide you a sample project with a working application.

Description of the problem

You have a component which adds some event listener inside useEffect() block. You wrote some unit test, but quickly realised that your unit test runs the code inside useEffect, but it does not run the function that your event listener is adding. So, you should basically mock addEventListener to solve it, but how?

Sample Project: offline-modal

offline-modal is a simple application which utilizes online/offline events. (See reference here: developer.mozilla.org)

When you turn off internet on your machine (or by using the throttle functionality on Chrome), the application shows some information to the user. After the connection is asynchronously restored, the user receives the feedback about connected internet for 3 seconds. And this message also finally disappears.

Offline Modal Demo

Implementation of offline-modal > OfflineModal.tsx

Before we jump into the unit testing discussion, it is wise to review the implementation.

const OfflineModal: React.FC = () => {
    const [connStatus, setConnStatus] = useState<number>(ConnectionStatus.Online);
    const connStatusRef = useRef(connStatus);
    connStatusRef.current = connStatus;
    useEffect(() => {
        const toggleOffline = () => {
            setConnStatus(ConnectionStatus.Offline);
        };
        let timer: NodeJS.Timeout | undefined;
        const toggleOnline = () => {
            setConnStatus(ConnectionStatus.SwitchingOnline);
            timer = setTimeout(() => {
                if (connStatusRef.current !== ConnectionStatus.Offline) {
                    setConnStatus(ConnectionStatus.Online);
                }
            }, 3000);
        };

        window.addEventListener('online', toggleOnline);
        window.addEventListener('offline', toggleOffline);
        return () => {
            window.removeEventListener('online', toggleOnline);
            window.removeEventListener('offline', toggleOffline);
            if (timer) {
                clearTimeout(timer);
            }
        };
    }, []);

I will explain the critical lines here.

Line 2: This our state management which keeps track of current connectivity status.

Line 19 and 20: I basically add event listeners to follow connection status here. Two separate functions are assigned to online and offline cases.

Line 22 and 23: Before the component (OfflineModal) is unmounted, we remove the event listeners.

In the latter part of the component, I render 3 different connection status (Offline, SwitchingOnline, Online) in a Switch statement to inform the user. That’s basically it.

Unit Test Implementation > OfflineModal.test.tsx

This is the critical part. I wrote the function below to mock internet connection in Jest environment.

const mockInternetConnection = (status: string) => {
    const events = {};
    jest.spyOn(window, 'addEventListener').mockImplementation((event, handle, options?) => {
        // @ts-ignore
        events[event] = handle;
    });
    const goOffline = new window.Event(status);
    act(() => {
        window.dispatchEvent(goOffline);
    });
};

Line 1: I created a parameter called status. In this example, example input could be ‘online’ or ‘offline’ string values. These are actually the event names to be added.

Line 2: An empty json object is created.

Line 3: The core of mocking happens in this scope. We spy on window.addEventListener call. Whenever subject code runs this function in due implementation, we will add the corresponding event type into its events array. So that, we will be able to run requested event in our unit test. This event can be any other event such as click, keydown, etc.

Line 7: This line creates a fake event. But it does nothing on its own. I only assigns the fake event object into a const called goOffline.

Line 9: Here we trigger our fake event just like the implementation code does in reality.

After creating the function (mockInternetConnection), writing the unit test suite is much simpler.

describe('OfflineModalComponent', () => {
    it('switches offline and back online', () => {
        render(<OfflineModal />);
        mockInternetConnection('offline');
        expect(screen.getByText('You are offline')).toBeInTheDocument();
        mockInternetConnection('online');
        expect(screen.getByText('It worked! You are back online! :)')).toBeInTheDocument();
    });
});

This unit test turns off the user’s internet connection and verifies the correct output. Later on, it switches the connection back online and runs one more check.

I hope this blog post helps you solve a similar problem on your side 🙂 Good luck!

Here is the link to the GitHub repository: https://github.com/SercanSercan/storksnest/tree/master/offline-modal

Sercan Leylek

6 Advice on Mixpanel Integration

User analytics is one of the most fundamental features that every popular web application should perform. Without collecting data about user activities, one can never be sure of the user experience. The developer team will invest days on some functionality, but unless they know how many users use this precious feature, they will only guess and hope that the users are benefiting from it.

In other words, “Without data you’re just another person with an opinion.”, W. Edwards Deming.

To clarify the ambiguity, my production team (http://meldeskade.no) decided to use popular business analytics tool, Mixpanel. Our single page web application is built with ReactJS, uses Jøkul Design System and hundreds of users visit the website to report their insurance activities every day. In short, meldskade.no is a typical SPA which promises the user to follow a set of operations under some sections and completes the user request somewhere along the way.

From the perspective of a front-end developer, I thought including Mixpanel tracking would be a simple task. However, as our team gained more and more experience in the field, I started to realize the obstacles. We followed the path of ‘learning by doing’ and eventually, our Mixpanel tracking started to deliver us data. So, this article will help to those who are in the beginning of their Mixpanel journey and looking for some useful advice.

#1 Don’t underestimate the integration work

Know your enemy first! Adding Mixpanel to your web application is an integration process and system integration is maybe the most problematic fields in Information Technology. Because linking different systems increases the complexity. Although the relationship between a web application and Mixpanel is a one-way road, the integration will still be painful, and it has the potential to produce unforeseen errors.

For instance, if you perform some tracking event before initializing the Mixpanel with the code below, the application will have a fatal error and whole website will be down for the user. This error can seem obvious, but one exceptional case for some users might be the end of the show. Therefore, do not underestimate the complexity of integration process.

import { MixpanelUtils } from './MixpanelUtils';
...
MixpanelUtils.Init();

#2 Document every tracking operation first, code later

Teamwork is required in order to integrate a web application with Mixpanel. Naturally, a web developer cannot sit alone and write all the tracking operations on his/her own for a large system. Product owner, architect, tester, and tech lead should give their consent on what user activities will be tracked besides developers. Since people from different roles are involved in the process, it is important to keep decisions in one open document.

The team of meldskade.no created a table which lists all tracking events. We included many columns for every event such as definition, trigger case for the tracking, its parameters, development status and we even wrote down the JIRA ticket for each tracking. This strategy helped the team solve the complexity of the problem.

Besides, we still keep this document active. Whenever the team needs to implement a new Mixpanel tracking, we start the work by documenting. So, document first, code later.

#3 Don’t try to track too many events on first deployment

Since our team underestimated the complexity of adding Mixpanel to our website, we set an ambitious goal for our delivery. We tried to implement at least 10 different tracking operations in one go. However, you should also implement configuration code for Mixpanel. These are OptInTracking, alias, identify, getting cookie consent of the user, etc. This is the threshold that one team should initially come over to reach for tracking events. When a team wraps all of these in a single deployment, the development work grows much more than expected. Therefore, the goal on first deployment should be a successful configuration of Mixpanel and a couple of meaningful tracking operations.

#4 Surprise! Surprise! You need a backend developer 😀

This is a point that our team failed to foresee. We basically thought we had all the data out there. We should only write some well-organized tracking operations in JS and everything will go smoothly. However, the data flow of a web application is not like what you see on a webpage as a human being. For example, you want to track some category data after the user clicks a section, but the component that you are triggering the event from may not contain the category information as a prop. Therefore, you need to ask the backend developer to provide this additional data via corresponding API call.

This tip is very much related to the advice #2. If the developers communicate about where and how to obtain the data attributes in the documentation, the process will go simultaneous and smooth.

#5 You will discover defects along the way

This might be one of the greatest paybacks for all the effort performed to reach the goal. As you implement more tracking on different components of a React application, you will discover some defects that have been omitted by you and other fellow front-end developers. React redundant rendering problems are known, but mostly ignored defects. And they are not easily discovered by tester, neither they truly create some run time error, but they are there. While adding more tracking operations, you will clearly see those mistakes and you will have the opportunity to fix them with some refactoring process. This practice will increase the performance of the application.

#6 GDPR is everyone’s responsibility. Speak up when in doubt.

Every team member should be observant on potential GDPR violation. More data does not help to understand user interaction better, but key data does. Users’ private data does not play any role while measuring the efficiency of an application. Therefore, speak up when you are in doubt of some data that your team is about to collect.

Sercan Leylek

Finishing Master’s Degree in Seven Years

I admit the fact that the title of this article sounds like a movie name. In other words, I did not travel as much as Brad Pitt did in Seven Years in Tibet, but my master’s degree has also been a challenging academical adventure.

Most people reach their master’s degree between 2 to 3 years. They start their master studies right after the undergraduate programme, and they follow master courses besides some part-time work. However, I did not have this luxury. After completing my bachelor studies in Turkey, I had to get a full-time job in IT (2009). After I established my financial freedom in a couple of years, I decided to follow master’s degree in IT at University of Oslo (2014).

5 years of work experience helped me realize the value of master studies. In 2009, I was not quite aware of its significance, but I came to the conclusion that completing some master’s degree is a good career and personal development investment.

In 2014, I talked to my manager at Thomson Reuters and we reduced my working hours by 40%. I was supposed to pass three courses in the first semester, so I worked at my professional job 3 days a week. However, I managed to pass only two courses because it was not possible to follow all theoretical and lab lectures of three courses with only 2 workdays free in a week. Meanwhile, my monthly income naturally cut by 40% and this quickly ended up having minor financial problems for myself.

In the spring semester of 2015, I worked 4 days a week and aimed to pass only one course. This tactic paid better since I managed to create some balance between financial independence and academical growth. However, it was certainly not enough. Because I was supposed to get 60 credits in my first year, but I had managed to get only 30 credits.

In fall 2016, I picked some completely wrong course for myself and got away from master’s degree. I had also consumed my energy and focus. And at the end of first two years, the University of Oslo kicked me out of master’s programme since I did not manage to finish it on time.

After this period, I enrolled at master studies once more, but my request was denied. (2017) The university aims to give the chance of study to almost everyone, but if you failed once, you are not welcome as you applied for the first time. I applied once more, and rejected once more. (2018) This time, I sent an e-mail to the university and asked about why I had been rejected. And they said I was rejected because of my lack of academical growth. This is actually polite way of saying this: “You only got 30 credits in 2 years. If you somehow manage to gain more credits, we may consider to accept you back”.

I decided to change my strategy after this news and learned about “Admission to Single Course Studies”. It roughly works this way:

  • The university places every student at some course.
  • Every semester, some courses lack students.
  • They open admission for outsiders (like me) for these courses.
  • You are allowed to pick one among 2 or 4 courses.
  • If you manage to pass your selected course, you get 10 credits.

Good deal! Following this path, I applied a course almost every semester and started to collect 10 credits once in a while. I was not able to pass a course every semester because I did not have any suitable course for me at some semesters, but I managed to collect 30 more credits within two more years. As a sum, I had 60 credits. In other words, I managed to become a more attractive student for the board which decides who would be accepted to the master’s programme. And this plan worked.

In fall 2020, I have been officially re-accepted as a master student at University of Oslo. To be able to graduate, you need to have 120 credits in total and my lacking 60 credits were locked behind a successful master thesis wall. At that time, I have been lucky to meet my current employer Fremtind AS. They had been implementing something called “design system”. It was completely new to me at that time. As I learned more about design systems, I started to see the connection with platforms. I had learnt about platforms at one of my single courses and managed to tie these two worlds for my master thesis. This process helped me write my thesis about some topic which I actually work in a daily basis. Finally, I delivered my thesis in December 2021 and finished my master’s degree.

Pros and cons of my path

Taking master courses besides professional work is definitely not easy. You have to dedicate your evenings and weekends to reading research papers, preparing homework and passing final exams. This is lots of stress, but it is a great opportunity to discover one’s true potential. I apparently enjoyed reading many research papers. You have to read lots of things, but these valuable articles contain surprising secrets. When you experience such aha moment, it builds up your character and you start seeing patterns from multiple perspectives.

Moreover, academic studies are mostly about theory, but I was at a practical world at the same time. I was able to apply some new knowledge that I gained at a lecture immediately at my working hours. I realized this advantage already in the first weeks of my path. You learn some new thing at school, you get to the work and apply it instantly. This is luxury in professional life.

As you see, I had to take a painful path for my master’s degree, but I have been stubborn enough to get it done. I honestly don’t know how many times I thought I would quit and sometimes I even quit this dream, but reconsidered the situation and applied a new remedy to get over the obstacles.

Instead of struggling with master’s degree, I could have invested in a startup idea, some framework or anything else, but that was what I wanted for myself. I did not want to die without knowing what was academical life all about and I definitely think that it was worth it.

I hope this story inspires more people out there struggling with similar challenges. You may stop believing in yourself, take a rest if you fall down, but just for a while. Then, keep moving towards your goal.

Sercan Leylek / OSLO

Calculating Distance in Google Maps with React and Typescript

After a long pause, I am back to my Google Maps application. In other words, the 3rd video of the series is out! In this video, our Google Maps application turns out to be something useful. The application lets the user calculate distance between some points on the map. Below is the list of tasks completed in part 3:

  • Create home address marker with center and zoom functionality (panTo and setZoom)
  • Calculate distance between home address marker and custom markers (computeDistanceBetween)
  • Draw a line between home and selected marker (polyline)

Github URL: https://github.com/SercanSercan/youtubeStuff/tree/master/google-maps

This article will point out some of the critical code snippets in the video. I prefer to make up some questions that you may ask along the way.

1. How to create markers with PNG files?

You don’t have to use SVG content to create markers in Google Maps. In some cases, you may prefer to use PNG instead. For example, while creating the home marker of my application, I used a PNG file. Place the image into some folder that is located under your public folder (such as public/assets/images/…) and the icon attribute of your google.maps.Marker constructor receives the url parameter as shown below.

const homeMarkerConst:GoogleMarker = new google.maps.Marker({
    position: location,
    map: map,
    icon: {
        url: window.location.origin + '/assets/images/homeAddressMarker.png'
    }
});

2. How to create an event for a marker in Google Maps?

You can implement some operations on markers via adding event listeners on them. Preferably, you should add your event listener and the corresponding function right after you create the marker. The code snippet below shows the event listener that I added to my home marker. The arrow function changes the center point of the map with the location of home marker.

homeMarkerConst.addListener('click', () => {
    map?.panTo(location);
    map?.setZoom(12);
});

The gif animation below shows how this listener performs in the application. After the user clicks on home marker, the map centers and sets the zoom level to 12.

Homework! 👀

As you see, my zoom operation in the code snippet above is not actually smooth. Clone my repository and create a function called smoothZoom. This function should zoom gradually. I want you to change the zoom level in every 100 milliseconds. (💁 Hint: smoothZoom should be recursive)

3. How to compute distance between two markers in Google Maps?

We so far learnt how to perform some function when a marker is clicked, right? So, if I should calculate the distance when a marker is clicked, what am I supposed to do? The answer is adding another click event listener. Before that, you should add another library to your Api URL. If you’d like to calculate distance in Google Maps, you should use the function computeDistanceBetween(…, …). This function lies under geometry library of Google Maps library. Therefore, your Api URL should be something like this:

maps.googleapis.com/maps/api/js?key=${your_key}&libraries=geometry,places&language=no...

After making sure that libraries have geometry, now I can add the click event listener which gets the position of two markers and computes the distance between them.

marker.addListener('click', () => {
    const homePos = homeMarker?.getPosition();
    const markerPos = marker.getPosition();
    if (homePos && markerPos) {
        const distanceInMeters = google.maps.geometry.spherical.computeDistanceBetween(homePos, markerPos);
        console.log(distanceInMeters);
    }
});

After adding polyline code and few more other things, the code above helped me measure the distance between home marker and custom markers as the gif below shows:

4. How to use React Hooks inside marker event listener?

This is the most challenging part while implementing Google Maps with React. The event listeners are part of vanilla javascript and they have no respect against the render mechanism of React. They only remember the hook values of the moment that you added the listener. Therefore, when you try to perform some setter operation of a hook, its value will not always be updated. I mean the hook value will actually be updated, but your listener functions may still remember the former value of the hook. (I know! This part is a bit complex. So, read this paragraph again and ponder)

To fix this, you should remove your listener function and add it again. So that, your new listener event will keep the updated version of your hook value. Therefore, I keep the listener ids of my events in a hook array and whenever I am supposed to update some hook value inside the event listener, I remove all previous listeners and add them again. I won’t share a code snippet for this part, so you’d better watch the last 20 minutes of the video 😁

Hopefully this blog post will help someone in the future! And again hopefully I will make the 4th video some time soon.

Sercan Leylek

TypeError: Class constructor HTMLElement cannot be invoked without ‘new’

This error message has been a headache for me this week. I noticed that there were no good posts to cover it in the internet, so I decided to write this post. Hopefully, it will help someone in the future.

Technology stack

  • React
  • Typescript
  • testing-library/react
  • Jest

Definition of the problem

This error occurs while running a unit test. The component that you are running has probably some 3rd party code which contains class components and your EcmaScript configuration in tsconfig.json is not able to compile this file. Therefore, your test fails at some random point in the 3rd party code.

Solution

Unfortunately, there is no single solution for this error because every environment has its own problem because of similar situation. I will show how I handled it while I was using NRK’s core library.

1) Install custom elements es5 adapter for your project.

npm i custom-elements-es5-adapter

2) Import custom elements adapter to your setupTests file

import '@webcomponents/webcomponentsjs/custom-elements-es5-adapter';

3) Run your test again. It should work 🙂

Sercan Leylek

Highlights of Beyond Design Sytems Meetup

Insurance company Fremtind organised a design system meetup on November 4th. The name of the event is Beyond Design Systems. The text below summarises the purpose of the gathering:

“The digital product industry has been welcoming design systems for a while. Many organizations have been better able to preserve brand guidelines, speed up time-to-market, or improve the user’s experience by establishing and maintaining a functioning design system.

This event will attempt to look beyond: To uncover the good, the bad, and the ugly experiences from inside our design systems. What has thrilled users? Where has it gone wrong? How did we prevail – if at all?”

Because of Corona measures, the event was broadcasted online via company’s youtube channel. The experts who are located in different parts of the globe have been available via a YouTube URL. That was quite comforting. If you are eager to learn about design systems, you can watch the whole session below:

Meetup – Beyond Design System – Fremtind – November 2020

what is a design system?

There are several definitions out there, but I will describe it with my words: A design system is a collection of design rules, patterns and reusable elements which help a web application develop faster and in a correct way.

For example, almost every web application requires a loading animation, footer, date box, etc… Most of these elements are common in every project and they all require time to build, consistent style, accessibility, validation, standard UX, UI guidelines and more. So, the design system assists your project to cover those needs at reusable parts of the final outcome. Therefore, digital product industry has been recently moving towards design systems.

Highlights

“Design systems should be built on collective culture, not individual achievement.”

Above is a quote from Glenn Brownlee who is the leader of design system, Jøkul. The inclusion of people are needed to make a design system work. If people do not participate, then there would be no progress. Brownlee basically underlines that a design system is actually a living thing. It evolves and the people need to understand why the system is necessary. As the process matures, actors of design system will not follow the rules just because they are told to do so, but they will see these rules as an expected way of doing. In other words, the rules will become their new normal. 

Brownlee also added: “If all you have is a component library, you don’t have a design system. However, once people become part of the movement, that means you have a design system.”

A similar thought was also mentioned by another participant of the meetup, Mike Hall (UX Lead for the Service NSW Transactional Design System). Hall said that if a system was not updated and maintained, it would die very quickly.

I should confess that my favourite presentator of the meetup has been Eirik Fatland (Lead Designer at Fremtind). He mostly shared some of his interesting experiences while expressing his thoughts about design systems. That was truly engaging.

“In Fremtind, we for example have weekly design critique sessions that are important while establishing culture. In design critique session, anyone can bring any design they are working on and they receive feedback on it. Sometimes feedback leads to discussions. The discussions involve everyone in the room and they become wiser.” ~Eirik Fatland

And finally, Morgane Peng had a stunning presentation. She is the director of UX at Societe Generale. I think the Dunning-Kruger effect was a perfect example while she was explaining their design system journey.

The DunningKruger effect is a bias in thinking, usually where a person is unaware of how badly they grasp a subject, not understanding that they are failing at it. Peng says that she and her co-worker thought they built some useful tool in the beginning and afterwards they started to receive feedback and complaints from the users of their design system. Therefore, they fell to the valley of despair because of their mistakes. This experience helped them understand that building design systems is not easy. After putting more work and engagement with additional actors, they started to understand what they were actually building and before they reach to the plateau of sustainability, more partners joined them. As a result, Peng says that a design system is 20% craft and 80% people.

All in all, I hope there would be more interesting meetups soon. And if you are curious about design systems, I recommend you to take a look at this blog post: Everything you need to know about design systems.

Sercan Leylek

Creating Markers on Google Maps with React + Typescript

This is the part two of my Google Maps series. I don’t truly know where we are heading with this app, but I will keep teaching you the secrets of Google Maps programming with React and Typescript. Few days ago, I released the last video. This article serves as a cheatsheet of what I implemented on Youtube.

Creating Markers on Google Maps with React + Typescript (Part 2)

Link to GitHub Respository 

IMarker Interface and marker hook

First, we should create an interface for our marker, right? I want to keep three basic data attributes for a marker. Of course, the label of a marker could be also added here as another string value, but I want to keep things simple. Maybe we do it in the next video.

Based on this interface, I also create the marker hook which will store the content.

const [marker, setMarker] = useState<IMarker>();

Event Listener

While working with Google Maps on React, you should still write some Vanilla JS code as well. I don’t like this, but that’s the way it is. As soon as the map hook is initialised, we add a click listener into this function. This event listener will return us a latLng event object which will be used to get the coordinates from geocoder.

coordinateToAddress

As you notice, I invoke a function called coordinateToAddress() whenever the user clicks somewhere on the map. The click event of google.maps namespace returns us a typical event (e), but this e event has a special attribute called latLng. This is our location value. In this function, I pull three different data types from geocoder. I get the address, latitute and longitude. Just what I need to update with my marker hook.

At this point of the program, our Map component successfully retrieves the coordinates of clicked point and it stores the data in our hook (marker), but we do not illustrate any marker to the user, yet.

addSingleMarker

I created this function just for convention. If we decide to create an array of IMarker objects (which means storing several markers on the map at the same time), we would create another function called addMultipleMarkers. But let’s see what addSingleMarker() does first. It simply follows the changes on marker hook with a useEffect and whenever it is updated we invoke addMarker function.

addMarker

So, here is a much more reusable function. This is actually the place where our Map component will create the marker and it will show it to the user.

google.maps.Marker receives a JSON object where the options are almost limitless. There are so many attributes that you can use to customise your marker, but I only used fundamental parts here (position, map and icon). I also created a dummy function called getIconAttributes() which is only used for the output of icon. You may refer to Google Maps manual for further customisation.

Task

The gif animation below shows how I create markers on the map, but there is a problem. As I click a point on the map, the component successfully creates a marker. However, when I create once more, the previous marker is still there although the marker hook changed its value. So, try to create a function which will remove the previous function. Good luck!

I hope you enjoyed this post. I will keep on writing more about Google Maps. Take care!

Sercan Leylek / OSLO

Setting up Google Maps with React + Typescript

Coding with Google Maps is a fun, mysterious and challenging journey. If you do it with Typescript, both joy and pain get doubled.

When I was coding a Google Maps component at Fremtind fremtind logo, I was starving for a comprehensive tutorial on this topic. Unfortunately, the results were a bit disappointing, but like all developers I found a solution for each problem and the job was done. Then I asked to myself: Why not creating a comprehensive project and delivering all the secrets of my journey in one post?

Meanwhile I was working for my map component, I discovered the answers to my questions via different websites. For example:

  • How can I use typescript types from Google for my map project in React?
  • How should I load my Google Maps Api script into my homepage? What could be the best practice?
  • Where should I use “useRef” to point out my Google Maps DOM element?
  • ….

Some of the answers that I found were outdated, some people were not quite sure of what they were advising, etc… You know the drill.

As a result, I created a sample project at my GitHub repository and decided to sail for a new adventure as well. For the first time, I screencast a coding experience like an experienced youtuber. The duration of the video is 55 minutes and I let the audience view the whole process while I am coding the React project.

Link to GitHub Respository github-169-1174970

CODING NOTES

Setup and Installation

To kick off the project, we need to create a react application with typescript flag. Use the sample command below to start with:

npx create-react-app google-maps --template typescript

After cleaning up default stuff from the project (like deleting logo.svg, App.test.tsx, etc), run the command below to install Google Maps typescript types into your project as a node module element. This will help you access types from google.maps namespace. (Such as google.maps.Map, google.maps.LatLng, google.maps.MapTypeId, …)

npm install --save-dev @types/googlemaps

Bonus Hint: By doing so, you will also obtain google.maps.places.AutocompletePrediction type which can be used to build an address dropdown component.

Now we are ready to give a shape to our React project. I set up the file and folder structure of my src folder as blueprinted below:

src
├── App.css
├── App.tsx
├── Map
│   ├── Map.scss
│   ├── Map.tsx
│   └── index.ts
├── index.css
├── index.tsx
├── react-app-env.d.ts
└── utils
└── GoogleMapsUtils.ts

Implementing loadMapApi() Utility

While developing a Google Maps component, we need to load the script tag which will download the API library for us. At the end, our webpage should show something like this:

<script 
src="https://maps.googleapis.com/maps/api/js?key=<YOUR_API_KEY>&libraries=places&language=no&region=NO&v=quarterly"
async defer>
</script>

Before loading this tag into our DOM structure, we cannot run Google Maps related code pieces. Therefore, we should create a utility function under utils/GoogleMapsUtils.ts.

Screenshot 2020-08-16 at 21.29.09
loadMapApi() Utility Function

This function basically creates the aforementioned script tag and inserts it into the DOM if it is not found. loadMapApi() will be used by the page which calls our Map component. In my example, this page will be the homepage of the project (App.tsx).

App.tsx

In this application, we have two fundamental tasks for App.tsx. First one will handle loading the map utility and latter will call our custom Map component. To do that, I created the React hook below:

const [scriptLoaded, setScriptLoaded] = useState(false);

This hook makes sure that Google Maps script tag is loaded successfully into the page. When scriptLoaded hook is set true, App.tsx renders my custom Map component.

useEffect(() => {
    const googleMapScript = loadMapApi();
    googleMapScript.addEventListener('load', function () {
        setScriptLoaded(true);
    });
}, []);

useEffect hook above runs when App component is mounted and when the script is loaded, we are ready to render Map component as shown below:

return (
    <div className="App">
        {scriptLoaded && (
            <Map
              mapType={google.maps.MapTypeId.ROADMAP}
              mapTypeControl={true}
            />
        )}
    </div>
);

Map/Map.tsx

We finally reached to the heart of the application. Map.tsx is my custom map component that I mentioned under the previous title. Let’s create its interface (IMap) first.

interface IMap {
    mapType: google.maps.MapTypeId;
    mapTypeControl?: boolean;
}

I wanted to receive two basic props. mapType can have ROADMAP, SATELLITE, TERRAIN or HYBRID values. These are specific map types defined by Google.

Screenshot 2020-08-16 at 22.04.24
google.maps.MapTypeId.ROADMAP

 

Screenshot 2020-08-16 at 22.06.29
google.maps.MapTypeId.SATELLITE

And we will use mapTypeControl prop to show/hide the control menu on the left-top corner of your map. We may extend the number of props to increase the usability of our map component, but I wanted to use only two props to illustrate my example.

I also use typescript’s custom type definition feature to increase the readability of my source code.

type GoogleLatLng = google.maps.LatLng;
type GoogleMap = google.maps.Map;

Before I explain the initMap, defaultMapStart, and startMap functions, I would like to show you the render part of the Map component.

const ref = useRef<HTMLDivElement>(null);

return (
<div className="map-container">
 <div ref={ref} className="map-container__map"></div>
</div>
);

The inner div element is the reference point for Google Maps. The API will load my map content into this div element and I use the outer div just for styling purposes. On the other hand, the same ref value is used by initMap function where the map is triggered.

Screenshot 2020-08-16 at 22.31.48
initMap function and map hook

As you see above, before implementing the initMap function, I created a hook called map. This hook is used to keep the map object created by google.maps.Map(…) function. The same function takes our div element via ref.current as its first parameter and the second parameter is a json object which keeps the preferences of our map.

initMap receives two inputs: zoomLevel and address. zoomLevel is straightforward to understand, but what address does will be more clear when we take a look at defaultMapStart() function.

Screenshot 2020-08-16 at 22.37.33
defaultMapStart function

So, this function basically calls the initMap, but it also does some critical work as well. It decides where to focus and how much to focus when our map starts.

Screenshot 2020-08-16 at 22.46.40
startMap function

Finally, startMap function calls defaultMapStart() when the map hook is not null anymore. This check is necessary because of rendering delays and typescript will complain if you do not run this check.

CONCLUSION

This application may not seem so impressive in terms of functionality, but you see that we had to do a lot of things just to start our map. While shooting the video, I had a problem with the API key because I did not want to screencast it via my youtube video, but when I include it, the output is as shown below:

Screenshot 2020-08-16 at 22.04.24
Final output

I am planning to screencast a second video where I will show how to add/remove markers on Google Maps. I hope you enjoyed this tutorial 🙂

 

Sercan Leylek / OSLO

Is it possible to trigger two DOM events at the same time on React?

Few weeks ago, I found myself desperately googling this question while I was trying to fix a React glitch. The answer is certainly, No! DOM is made to receive one user interaction event at a time, but I wanted to get rid of this error so badly and I was still hoping that there could be a way.

Let me clarify the case with a more elaborative example. I created a simple typeahead component which can be downloaded via https://github.com/SercanSercan/storksnest/tree/master/simple-typeahead

simple-typeahead-demo
Simple typeahead component demo

As the gif image above declares, there are two basic UI elements in a typical typeahead component: There should be a text box and a list of items that become visible upon user interaction. Component should also have some keyboard navigation where the glitch pops up.

Please take a look at the render part of the typeahead:

Screenshot 2020-05-24 at 18.40.08
Core render of typeahead component

Typeahead basically has the following DOM structure

  • div.typeahead => wrapper
    • input => textbox
    • ul => unordered list
      • li => list item to show a capital
      • li => list item to show a capital

As the code snippet above shows, when the user sets the focus on input, showSuggestions hook is set true. Hence, unordered list becomes visible. I did this by using onFocus and onBlur events. This is quite straightforward thinking. If the user tabs through my text box, dropdown will be shown to user and it will be hidden on the next tab. However, when the user clicks on a list item (to select a capital), onBlur got triggered although I wanted to trigger my onClick event on <li/>. Therefore, I quit using onClick event and used onMouseDown instead. Then, typeahead component worked like a charm 🙂 As a result, I couldn’t trigger two DOM events at the same time, but found a way to orchestrate related events. This should be the approach to solve such problems among UI events.

BONUS MATERIAL => Jøkul’s useKeyListener hookstorksnest_jøkul_bonus_useKeylistener_hook

Aforementioned application (simple-typeahead) can be inspiring for those who are about to develop their own dropdown component. At this point, I would like to introduce you a promising UI library called Jøkul. This library provides you stylish UI components (checkbox, datepicker, progressbar, etc. ) while creating your SPA. In my application, I benefited a custom hook from Jøkul. So, how to use Jøkul’s useKeyListener hook?

Step 1:

Install jkl-react-hooks on your web app:

npm i @fremtind/jkl-react-hooks

Step 2: 

Import useKeyListener under your target component:

import { useKeyListener } from '@fremtind/jkl-react-hooks';

Step 3: 

Identify the set of keys that you will use. In my case, I needed to use following list of keys:

const keys = ['ArrowUp', 'ArrowDown', 'Enter', 'Escape'];

Step 4: 

Create a reference for your input element:

const ref = useRef(null);
...
<input ref={ref} ...

Step 5:

Program it your way! As the code snippet below indicates, I created a function called onKeyPressed and sent it to Jøkul’s useKeyListener. Besides, my function consists of nothing but a switch case where I implement expected output. For example, if the user presses arrow down key, I increment the value of selectedIndex as long as it is within the length of my suggestions list.

Screenshot 2020-05-24 at 19.09.59

Jøkul’s useKeyListener stops you googling key codes and your source code becomes more readable and neat.

Sercan Leylek / OSLO