Amplify auto-detecting my React app
Strategy

Amplify auto-detecting my React app’s framework as "Web…


Amplify auto-detecting my React app's framework as "Web" instead of "React"

And because of this, I keep getting a 403 error where it says "This XML file does not appear to have any style information associated with it"

https://preview.redd.it/l41iikhgmek51.png?width=1576&format=png&auto=webp&s=b37874b393bc4d513cc98b7e4c16089f7f141e3b

submitted by /u/usernaame001
[comments]



Source link

Learning Web Development -Applied Accessibility for today
Strategy

Learning Web Development -Applied Accessibility for today


Learning Web Development -Applied Accessibility for today

Sup boys and girls i'm live on twitch learning some next level Applied Accessibility for today. Come round and see what's that ? ? https://www.twitch.tv/cleverlys13

https://preview.redd.it/m3elsel5sdk51.png?width=829&format=png&auto=webp&s=99a0c2a233a7e02371d4fcc66ccf1beb5df18a7b

submitted by /u/juneshour
[comments]



Source link

a logo i am working on - would love to get some feedback
Strategy

a logo i am working on – would love to get some feedback


a logo i am working on - would love to get some feedback

the companies name translates to "rock and color" and it sells retro style illustrations of mountains. i feel like it looks a little too smooth and precious? what do you think?

https://preview.redd.it/g7b5t6hfpdk51.png?width=1774&format=png&auto=webp&s=af9d1716a122fe6b811690d408f0e3e55429b172

submitted by /u/bellcent
[comments]



Source link

Angular, Docker, and Spring Boot: A Match Made in Heaven
Strategy

Angular, Docker, and Spring Boot: A Match Made in Heaven


Angular and Spring Boot are extremely popular, and used often while creating modern apps. When looking for popular search terms in Google’s Keyword Planner, these two together appear often. What comes out of this is a summary of monthly searches, which are unlimited by location, and averaged.

A series of tutorials on Angular and Spring Boot has led to this fourth and final tutorial. Throughout this series one is taught how to use Angular and Spring Boot + Kotlin in order to create a more secure notes app, how to add Bootstrap for CSS, as well as making it easy to interact with data tables. Second to last, the tutorials show how to deploy apps separately to  Heroku. In addition to this, the tutorial shows how to use the ng deploy to deploy AWS, Firebase, and Netlify. Tutorials are linked below. 

  1. Build a CRUD App with Angular 9 and Spring Boot 2.2
  2. Build Beautiful Angular Apps with Bootstrap
  3. Angular Deployment with a Side of Spring Boot

In this tutorial, I will be outlining the use of Docker in order to create images for Angular, and deploy said images to Heroku, how to use both Angular and Spring Boot into the same JAR artifact for deployment. I will also include how to Dockerize combined clips using Cloud Native Buildpacks and Jib, and how to deploy personal Docker images to Cloud Foundry, Knative on Google Cloud, and Heroku.

The most popular way to build and share containers is by far Docker. ‘Dockerizing’ is when you package your app, which can also involve adding web servers to your app. When containerizing an Angular app, this can become very important because an Angular app only has its artifacts as JavaScript, CSS, and HTML, which means that the product app will need to serve up its static files by a web server. If you are worried about security, the webserver has the ability to send security headers by configuring it, making it much safer for users.

Table of Contents

I’d like to thank many folks for their help with this post. Benoit Sautel for help with Gradle + Kotlin, Ray Tsang for help with Jib, James Ward for help with Knative, Josh Long for his assistance with Docker + Cloud Foundry, and Joe Kutner for his buildpacks support. Y’all rock! ��

You can also watch this tutorial as a screencast!

To begin, clone the GitHub repo from the most recent tutorial in this series.

   

Prerequisites:

Secure Your Angular + Spring Boot App with OpenID Connect

OAuth 2.0 was finalized in 2012 and has since become the industry-standard protocol for authorization. In 2014, OpenID Connect (OIDC) extended OAuth, adding federated identity to delegated authorization. Together, these two layers offer a standard specification that developers can write code against in a way that will work across multiple identity providers.

To begin the process of adding OIDC to Angular and Spring Boot, you’ll need to create a Heroku account. If you already have a Heroku account, log into it. Once you’re logged in, create a new app. I named mine bootiful-angular.

After creating your app, click on the Resources tab and add the Okta add-on.

If you haven’t entered a credit card for your Heroku account, you will get an error. This is because Heroku requires you to have a credit card on file to use any of their add-ons, even free ones. This is part of Heroku’s assurance to guard against misuse (real person, real credit card, etc.). I think this is a good security practice. Add a credit card to continue.

Click Provision and wait 20-30 seconds while your Okta account is created and OIDC apps are registered. Now go to your app’s Settings tab and click the Reveal Config Vars button. The variables displayed are the environment variables you can use to configure both Angular and Spring Boot for OIDC authentication.

Create an okta.env file in the angular-spring-boot-docker/notes-api directory and copy the variable values into it, where $OKTA_* is the value from Heroku.

Start your Spring Boot app by navigating to the notes-api directory, sourcing this file, and running bootRun.

For Windows users, the commands will be:

Next, configure Angular for OIDC authentication by modifying its auth-routing.module.ts to use the generated issuer and SPA client ID.

notes/src/app/auth-routing.module.ts

Install your Angular app’s dependencies and start it.

Open http://localhost:4200 in your browser.

Click the Login button in the top right corner. You should be logged in without seeing a login form because you’re already logged in to Okta. If you want to see the full authentication flow, log out, or try it in a private window. You can use the $OKTA_ADMIN_EMAIL and $OKTA_ADMIN_PASSWORD from your Heroku config variables for credentials. Create a note to make sure everything works.

Commit your progress to Git from the top-level angular-spring-boot-docker directory.

Create a notes/Dockerfile that uses Node and Nginx as a web server.

When I was trying to get everything to work, I found it handy to comment out the RUN ng build --prod line and use the following instead.

This allows you to skip the lengthy Angular build process.

This will build your project and add Nginx as a web server. You’ll need to create the nginx.config file to make Nginx SPA-aware.

notes/nginx.config

Make sure your Docker daemon is running with docker ps. Then run the following command to build your Docker image. The ng-notes value can be whatever you want to name your image.

If it builds successfully, you’ll see messages like the following:

You can run it locally on port 4200 using the docker run command.

Add these Docker commands as scripts to your package.json file.

The docker run command will serve up the production version of the Angular app, which has its backend configured to point to a production URL on Heroku.

notes/src/environments/environment.prod.ts

You’ll need to deploy your Spring Boot app to a similar public URL for your Angular + Docker container to work in production.

If you already deployed Spring Boot to Heroku (from the last tutorial), you can skip the next section and go straight to deploying your Angular Docker container to Heroku.

Deploy Spring Boot to Heroku

One of the easiest ways to interact with Heroku is with the Heroku CLI. Install it before proceeding with the instructions below.

Open a terminal and log in to your Heroku account.

You should already have a Heroku app that you’ve added Okta to. You can use it for hosting your Spring Boot app. Run heroku apps and you’ll see the one that you created.

You can run heroku config -a $APP_NAME to see your Okta variables. In my case, I’ll be using bootiful-angular for $APP_NAME.

Associate your existing Git repo with the app on Heroku.

Set the APP_BASE config variable to point to the notes-api directory. While you’re there, add the monorepo and Gradle buildpacks.

Attach a PostgreSQL database to your app.

By default, Heroku’s Gradle support runs ./gradlew build -x test. Since you want it to run ./gradlew bootJar -Pprod, you’ll need to override it by setting a GRADLE_TASK config var.

The $OKTA_* environment variables don’t have the same names as the Okta Spring Boot starter expects. This is because the Okta Heroku Add-On creates two apps: a SPA and a web app. The web app’s config variables end in _WEB. You’ll have to make some changes so those variables are used for the Okta Spring Boot starter. Run the following command and remove _WEB from the two variables that have it.

Now you’re ready to deploy! Heroku makes this easy with a simple git push.

By default, JPA is configured to create your database schema each time. Change it to simply validate the schema.

Now, you’ll need to configure your Angular app to use your Heroku-deployed Spring Boot app for its production URL.

notes/src/environments/environment.prod.ts

Since this runs the production build, you’ll need to add http://localhost:4200 as an allowed origin in your Spring Boot app on Heroku. Run the following command and add it to the end of the existing values.

One advantage of doing this is that you can run your local Angular app against your production backend. I’ve found this very useful when debugging and fixing UI issues caused by production data.

Now you should be able to rebuild your Angular Docker container and run it.

Open your browser to http://localhost:4200, log in, and confirm you can add notes.

Verify the data made it to Heroku by going to https://<your-heroku-app>.herokuapp.com/api/notes.

Heroku has several slick features when it comes to Docker images. If your project has a Dockerfile, you can deploy your app directly using the Heroku Container Registry.

First, make sure you’re in the notes directory, then log in to the Container Registry.

Then, create a new app.

Add the Git URL as a new remote named docker.

You’ll need to update nginx.config so it reads from a $PORT environment variable if it’s set, otherwise default it to 80. You can use envsubst to do this at runtime. However, the default envsubst doesn’t allow default variables. The good news is a8m/envsubst on GitHub does!

Replace your nginx.config with the following configuration that defaults to 80 and escapes the $uri variable so it’s not replaced with a blank value.

notes/nginx.config

You’ll also need to update your Dockerfile so it uses the aforementioned envsubstr.

notes/Dockerfile

Then, push your Docker image to Heroku’s Container Registry.

Once the push process has completed, release the image of your app:

And open the app in your browser:

You’ll need to add your app’s URL to Okta as a valid redirect URI. In your Spring Boot app on Heroku, go to Resources and click on the Ookta add-on. This will log you in to your Okta dashboard. Navigate to ApplicationsSPAGeneralEdit. Add the following redirect URIs.

You’ll need to add the new app’s URL as an allowed origin in your Spring Boot app on Heroku. Copy the printed Hosting URL value and run the following command.

Add the new URL after your existing localhost one, separating them with a comma. For example:

Now you should be able to log in and see the note you created earlier.

A-Rated Security Headers for Nginx in Docker

If you test your freshly-deployed Angular app with securityheaders.com, you’ll get an F. To solve this, modify your nginx.config to add security headers.

notes/nginx.conf

After updating this file, run the following commands:

Now you should get an A!

Commit your changes to Git.

In the previous sections, you learned how to deploy your Angular and Spring Boot apps separately. Now I’ll show you how to combine them into a single JAR for production. You’ll still be able to run them independently in development, but deploying them to production will be easier because you won’t have to worry about CORS (cross-origin resource sharing). I’ll also convert the OAuth flows so they all happen server-side, which is more secure as the access token won’t be stored in the browser.

Update Your Angular App’s Authentication Mechanism

Create a new AuthService service that will communicate with your Spring Boot API for authentication logic.

notes/src/app/shared/auth.service.ts

  1. Talk to the /users endpoint to determine authenticated status. A username will be returned if the user is logged in.
  2. When the user clicks a login button, redirect them to a Spring Security endpoint to do the OAuth dance.
  3. Logout using the /api/logout endpoint, which returns the Okta Logout API URL and a valid ID token.

Create a user.ts file in the same directory, to hold your User model.

notes/src/app/shared/user.ts

Update app.component.ts to use your new AuthService in favor of OktaAuthService.

notes/src/app/app.component.ts

Remove OktaAuthModule and its related code from app.component.spec.ts and home.component.spec.ts. You’ll also need to add HttpClientTestingModule to their TestBed imports.

Change the buttons in app.component.html to reference the auth service instead of oktaAuth.

notes/src/app/app.component.html

Update home.component.ts to use AuthService too.

notes/src/app/home/home.component.ts

Delete notes/src/app/auth-routing.module.ts and notes/src/app/shared/okta.

Modify app.module.ts to remove the AuthRoutingModule import, add HomeComponent as a declaration, and import HttpClientModule.

notes/src/app/app.module.ts

Add the route for HomeComponent to app-routing.module.ts.

notes/src/app/app-routing.module.ts

Change both environments.ts and environments.prod.ts to use a blank apiUrl.

Create a proxy.conf.js file to proxy certain requests to your Spring Boot API on http://localhost:8080.

notes/src/proxy.conf.js

Add this file as a proxyConfig option in angular.json.

notes/angular.json

Remove Okta’s Angular SDK and OktaDev Schematics from your Angular project.

At this point, your Angular app doesn’t contain any Okta-specific code for authentication. Instead, it relies on your Spring Boot app to provide that.

You should still be able to run ng serve in your Angular app and ./gradlew bootRun in your Spring Boot app for local development. However, you’ll need to make some adjustments to your Spring Boot app to include Angular for production.

Configure Spring Boot to Include Your Angular SPA

In your Spring Boot app, you’ll need to change a number of things. You’ll need to configure Gradle to build your Angular app when you pass in -Pprod, you’ll need to adjust its routes (so it’s SPA-aware and routes all 404s to index.html), and you’ll need to modify Spring Security to allow HTML, CSS, and JavaScript to be anonymously accessed.

To begin, delete src/main/kotlin/com/okta/developer/notes/HomeController.kt. You’ll no longer need this because your Angular app will be served up at the / path.

Next, create a RouteController.kt that routes all requests to index.html.

notes-api/src/main/kotlin/com/okta/developer/notes/RouteController.kt

Modify SecurityConfiguration.kt to allow anonymous access to static web files, the /user info endpoint, and to add additional security headers.

notes-api/src/main/kotlin/com/okta/developer/notes/SecurityConfiguration.kt

With Kotlin, you can mark parameters and return values as optional by adding ? to their type. Update the user() method in UserController.kt to make OidcUser optional. It will be null when the user is not authenticated, that’s why this change is needed.

notes-api/src/main/kotlin/com/okta/developer/notes/UserController.kt

Previously, Angular handled logout. Add a LogoutController that will handle expiring the session as well as sending information back to Angular so it can logout from Okta.

notes-api/src/main/kotlin/com/okta/developer/notes/LogoutController.kt

In OpenID Connect Logout Options with Spring Boot, Brian Demers describes this as RP-Initiated Logout. He also shows how you can configure Spring Security’s OidcClientInitiatedLogoutSuccessHandler to logout. I tried this technique but decided against it because it doesn’t allow me to redirect back to my Angular app in dev mode. I also encountered some CORS errors that I was unable to solve.

When you access the /user/notes endpoint with Angular, the ${principal.name} expression correctly resolves to the user’s email. However, when you access this endpoint after logging in directly to Spring Boot, it resolves to the sub claim. To make these values consistent, add the following property to application-dev.properties and application-prod.properties.

You can also remove the allowed.origins property from both files since Angular will proxy the request in development (eliminating the need for CORS) and there won’t be cross-domain requests in production.

Add a server.port property to application-prod.properties that uses a PORT environment variable, if it’s set.

Because there won’t be any cross-domain requests, you can remove the simpleCorsFilter bean and allowedOrigins variable in DemoApplication.kt, too.

Modify Gradle to Build a JAR with Angular Included

Now that your Spring Boot app is ready to serve up your Angular app, you need to modify your Gradle configuration to build your Angular app and package it in the JAR.

Start by importing NpmTask and adding the Node Gradle plugin.

notes/build.gradle.kts

Then, define the location of your Angular app and configuration for the Node plugin.

Add a buildWeb task:

And modify the processResources task to build Angular when -Pprod is passed in.

Now you should be able to combine both apps using ./gradlew bootJar -Pprod. Once it’s built, run it with the following commands to ensure everything works.

Congrats! You modified your Angular and Spring Boot apps to be packaged together and implemented the most secure form of OAuth 2.0 to boot! ��

Commit your changes to Git.

Since everything is done via Gradle now, you can use plugins to build a Docker container. Jib builds optimized Docker images without the need for deep mastery of Docker best-practices. It reads your Gradle/Maven build files for its metadata.

To add Jib support, add its Gradle plugin.

notes/build.gradle.kts

Then, at the end of this file, add jib configuration to specify your image name and the active Spring profile.

Run the following command to build a Docker image with Jib.

If you want to override the image name in build.gradle.kts, you can pass in an --image parameter. For example, ./gradlew jibDockerBuild -Pprod --image=bootiful-ng9.

Run Your Spring Boot Docker App with Docker Compose

In theory, you should be able to run the following command to run your app.

However, Spring Boot won’t start because you haven’t configured the Okta environment variables. You could pass them in on the command line, but it’s easier to specify them in a file.

You can use Docker Compose and its env_file option to specify environment variables.

Copy notes-api/okta.env to src/main/docker/.env.

Remove export at the beginning of each line. It should resemble something like the following after this change:

Create a src/main/docker/app.yml file that configures your app to set environment variables and leverages your existing PostgreSQL container. Make sure to replace the <your-username> placeholder and make the image match what’s in your build.gradle.kts file.

Docker Compose expects the .env file to be in the directory you run docker-compose from, so you have two choices:

  1. Navigate to the src/main/docker directory before running docker-compose
  2. Create a symlink to .env in your root directory: ln -s src/main/docker/.env

If you choose option #1, run:

Option #2 looks like:

Once you’ve verified everything works, commit your changes to Git.

Deploy Your Spring Boot + Angular Container to Docker Hub

Jib makes it incredibly easy to deploy your container to Docker Hub. If you don’t already have a Docker Hub account, you can create one.

Run docker login to log into your account, then use the jib task to build and deploy your image.

Isn’t it cool how Jib makes it so you don’t need a Dockerfile!? ��

To deploy this container to Heroku, create a new Heroku app and add it as a Git remote.

At this point, you can use the PostgreSQL and Okta add-ons you’ve already configured. If you’d like to do this, use addons:attach instead of addons:create in the following commands. Since both add-ons are free, I’m just going to show how to create new ones.

Add PostgreSQL to this app and configure it for Spring Boot using the following commands:

This fine-grained configuration is not necessary when you use Heroku’s buildpacks to deploy your Spring Boot app. It injects scripts that set SPRING_* environment variables for you. In this case, Heroku doesn’t know you’re using Spring Boot since it’s running in a container.

Add Okta to your app.

To see your database and Okta environment variables, run:

Modify the Okta environment variables to remove the _WEB on the two keys that have it.

Run the commands below to deploy the image you deployed to Docker Hub. Be sure to replace the <…> placeholders with your username and app name.

For example, I used:

You can watch the logs to see if your container started successfully.

Once you’ve verified it has started OK, set the Hibernate configuration so it only validates the schema.

Since the Okta Add-on for Heroku configures everything for you, you should be able to open your app, click the Login button, and authenticate!

If you test your Dockerfied Angular + Spring Boot app on securityheaders.com, you’ll see it scores an A+!

Heroku is awesome, but sometimes people want more control over their infrastructure. Enter Knative. It’s like Heroku in that it’s a Platform as a Service (PaaS). Knative is built on top of Kubernetes so you can install a number of services with a bit of YAML and kubectl commands.

With Heroku, when companies reach the limitations of the platform, they have to go elsewhere to host their services. With Knative, you can just drop down to Kubernetes. It’s Heroku for Kubernetes in a sense, but you don’t have to switch to a different universe when you need additional functionality.

The Knative website says it’ll make your developers more productive.

Knative components build on top of Kubernetes, abstracting away the complex details and enabling developers to focus on what matters. Built by codifying the best practices shared by successful real-world implementations, Knative solves the “boring but difficult” parts of deploying and managing cloud native services, so you don’t have to.

You’ll need a Google Cloud account for this section. Go to cloud.google.com and click Get started for free.

Once you have an account, go to Google Cloud Console and create a new project.

Then, click on the Terminal icon in the top right to open a Cloud Shell terminal for your project.

Enable Cloud and Container APIs:

This command can take a minute or two to complete.

When it’s done, set your default zone and region:

And create a Kubernetes cluster:

You can safely ignore the warnings that result from running this command.

Next, set up a cluster administrator and install Istio.

Now, you should be able to install Knative!

You’ll need a domain to enable HTTPS, so set that up and point it to the cluster’s IP address.

Install cert-manager to automatically provision and manage TLS certificates in Kubernetes.

And configure free TLS certificate issuing with Let’s Encrypt.

Phew! That was a lot of kubectl and YAML, don’t you think?! The good news is you’re ready to deploy PostgreSQL and your Spring Boot app.

The following command can deploy everything, but you’ll need to change the <…> placeholders to match your values first.

Once the deployment has completed, run the command below to change it so Hibernate doesn’t try to recreate your schema on restart.

If everything works correctly, you should be able to run the following command to get the URL of your app.

The result should look similar to this:

You’ll need to add this URL (+ /login/oauth2/code/okta) as a Login redirect URI and a Logout redirect URI in Okta in order to log in.

Then, you’ll be able to log into your app running on Knative! Add a note or two to prove it all works.

Did you know you can run Docker containers on Cloud Foundry? It’s pretty slick.

If you’d like to test it out, you’ll need a Pivotal Web Services account. You’ll also need to install the Cloud Foundry CLI. If you’re using Homebrew, you can use brew install cloudfoundry/tap/cf-cli.

Apps deployed to Cloud Foundry (CF) with the cf push command run in standard CF Linux containers. With Docker support enabled, CF can also deploy and manage apps running in Docker containers.

Then, where secure-notes is a unique name for your app, run the following commands.

At this point, you’ll need to set a number of environment variables so your app can connect to PostgreSQL and Okta. Substitute your values in the <…> placeholders before running the command below.

To get your PostgreSQL URL run the following command where secure-notes is your app name.

You will see a uri at the top of the output that has the URL you’ll need to parse and set as variables below. Make sure to replace postgres:// with jdbc:postgresql:// at the beginning of the datasource URL and extract the credentials for the username and password settings.

Your app, running in Docker, should now be available at http://<your-app-name>.cfapps.io.

You’ll need to add this URL (+ /login/oauth2/code/okta) as a Login redirect URI and Logout redirect URI on Okta in order to log in.

You’ll also want to configure JPA so it doesn’t recreate the schema on each restart.

Now you should be able to loginlog in and add notes to your heart’s content!

You can also just use a manifest.yml to make it so you don’t have to type all the commands above.

Since most of these environment variables should probably be externally specified, it’s not much gain to use the manifest.yml in this case. Storing secrets in source control is a bad idea!

If you do decide to store everything in manifest.yml, make sure to add it to .gitignore.

With a manifest.yml in place, you can simply run cf push and it’ll do the same thing as the aforementioned cf commands.

Cloud Native Buildpacks is an initiative that was started by Pivotal and Heroku in early 2018. It has a pack CLI that allows you to build Docker images using buildpacks.

Unfortunately, pack doesn’t have great support for monorepos (especially in sub-directories) yet. I was unable to make it work with this app structure.

On the upside, Spring Boot 2.3’s built-in support for creating Docker images works splendidly!

Spring Boot 2.3.0 is now available and with it comes built-in Docker support. It leverages Cloud Native Buildpacks, just like the pack CLI.

Spring Boot’s Maven and Gradle plugins both have new commands:

The Paketo Java buildpack is used by default to create images.

By default, Spring Boot will use your $artifactId:$version for the image name. That is, notes-api:0.0.1-SNAPSHOT. You can override this with an --imageName parameter.

Build and run the image with the commands below.

You should be able to navigate to http://localhost:8080, log in, and add notes.

Pretty neat, don’t you think!? ��

This lengthy tutorial showed you a lot of options when it comes to deploying your Angular and Spring Boot apps with Docker:

  • Build Angular containers with Dockerfile

  • Combine Angular and Spring Boot in a JAR

  • Build Docker images with Jib

  • Build Docker images with Buildpacks

You can find the source code for this example on GitHub at oktadeveloper/okta-angular-spring-boot-docker-example.

As a developer, you probably don’t want to do a series of tutorials to get to a baseline to start a project. The good news is JHipster does everything in this series. It allows you to run your Angular and Spring Boot apps separately, use Kotlin on the server, package your apps together for production, and use Docker for distribution.

To learn more about Angular, Spring Boot, and Docker, see some of our other blog posts.

Follow @oktadev on Twitter for more posts like this one. We also have a YouTube channel you might enjoy. As always, please leave a comment below if you have any questions!





Source link

Tree folder structure
Strategy

Recursive Angular Rendering of a Deeply Nested Travel Galler…


Suppose you like to travel and have collected a large photo gallery. The photos are stored in a tree folder structure, where locations are structured according to the geography and administrative division of a country:

Tree folder structure

The actual photos of particular places are stored in the corresponding leafs of the tree. Different branches of the tree may have different height. You want to show these photos in your portfolio website that is made on Angular. Also, the gallery should be easily extendible with new locations and photos.

The Problem

This problem statement is similar to that of my previous post. To show this gallery, we need two Angular libraries: angular-material-tabs and ivy-carousel or their equivalents. The tabs library provides a tree structure for the gallery locations, while the carousel shows the photos of a particular place.

Let’s take a look at a simple tabs example:

Here the tabs are grouped within the <mat-tab-group> tag. The content of an individual tab is wrapped in the <mat-tab> tag, while the tab title is the label value.

To add an extra level of tabs, one needs to insert a whole <mat-tab-group> block into an appropriate <mat-tab>. Clearly, such construct becomes very cumbersome and hard to extend as the gallery becomes sufficiently deep. So we need to automatically inject Angular template or component into the <mat-tab> elements and automatically pass the appropriate title to the <mat-tab label="title"> element.

Angular carousel works as follows:

The carousel content is wrapped into the <carousel> tag. Each individual image is wrapped into a <div class="carousel-cell"> tag. To show a large number of images in a tree folder structure, we need to automatically construct and provide a full folder path to every image into the src field.

Let’s see how to solve these problems in Angular.

The Solution

Firstly, there is a convenient data structure for this problem. Secondly, I demonstrate 3 separate approaches to render the data structure in Angular: a recursive template approach, a recursive component approach, and a recursive approach  with a single mutable shareable stack. The first two approaches are inspired by the post by . The last approach doesn’t duplicate data and illustrates the difference between the Angular and React change detection mechanisms. The code for all 3 approaches is here.

The Data Structure

Let’s pack our data to the following data structure:

This recursive tree pattern has nodes:

 and leafs:

Angular code for this data structure can be generated in a top-down recursive manner. All the grammar, production rules, and compiler theory arguments from my previous post are applied here as well. The Angular specific thing is how to pass the proper folder paths to each template or component.

Approach 1: Recursive Template

For this approach we need a node and a leaf templates. For the details look at this post. I focus on how to pass folder paths to the templates. So, the node template is:

This template accepts data (in the form described above) and path as input parameters. The this.key="children" is taken from the component; only 1 component is needed in this approach. At lines 4-5 the system determines if the child is a node, or a leaf. In the former case the system calls the treeView template again with item['children'] at lines 6-9. In the later case calls the leafView  template with item['children'] at lines 11-15.

The leaf template is 

Notice how the path is passed to the template. Since every Angular template has its own scope, we concatenate the previous path with the item.name. So, every template receives its own copy of the path and some of the path strings get duplicated in every node and leaf. There is no path.pop() anywhere.

The recursive process is initiated as

Here the data is our data structure and the this.pathStack=[].

Approach 2: Recursive Component

A very similar approach to the previous one. Here we replace the node template with a node component (see the post and the code for details). The component’s view is

{{item.name}}”>
0 && item[this.key][0][‘name’];
else elseBlock”>

” data-lang=”text/html”>

where the leaf template is already included. The component’s controller is:

No life cycle hooks are needed. Ones again the old path get concatenated with the item['name'] to get the new path

The recursion starts as 

where the data is the data structure, key="children", pathStack=[].

Every node component stores its copy of the path in the this.path variable. Is there a way not to duplicate the path data in node components?

Approach 3: Recursive Components With a Single Shareable Stack  

For this approach we need 2 components (for the node and leaf)  and 1 service (to store and modify a stack). The challenge here is how to use the component’s life cycle hooks to update the stack and to properly use the Angular change detection mechanism to provide the right stack to the right leaf.

The stack service (a singleton by default) is very simple:

The stack is stored as an array of strings. The service provides the push/pop and get operations on the stack.

The node component controller is:

The component receives the data array, path, and key string as inputs. The StackService is injected into the constructor. We use 2 component life cycle hooks to update the stack. A child folder name is pushed to the stack by the ngOnInit() hook. This hook is called only ones after the component initializes and receives its inputs from its parent component.

Also, we use the ngAfterViewInit() hook to pop the stack. The hook is called after all the child views are initialized. This is a direct analogue of pathStack.pop()of recursive JSX rendering, described in my previous post.

The node component view is quite simple:

Ones again, the system chooses what component, a node or a leaf, to render next. No path concatenations this time though.

The leaf component controller is 

Here I cut the corner and don’t use the ngAfterViewInit()hook to pop the stack. The this.fullPath variable gets computed ones in the ngOnInit()hook as the leaf component initializes. Finally, the leaf view is 

The key question here is why we can’t call this.stackService.getStack() directly in the template instead of first saving the call result in the fullPath variable and then interpolate the variable {{...+fullPath+...}}?

The reason is how Angular detects changes. Whenever the variables in the stackServce mutate, the onChange() component life cycle hook triggers in every component that calls the service. This happens since Angular sets a watcher on every interpolation {{…}}. So, whenever the stack gets pushed or popped, the {{this.stackService.getStack()}} would be called in every template of every component where there is such an interpolation. 

First, this would mean that all the templates get the same value (an empty string) of the stack after the DOM is fully rendered. Second, it would greatly slow down the browser since there will be a lot of calls.

The ChangeDetectionStrategy.OnPush doesn’t help in this case since the strategy only addresses the @Input parameters. The strategy prevents updates if the references to an input parameter object remains the same while the fields of the object get mutated.

React on the other hand detects changes differently. A React component is re-rendered if the component’s props change, setState(...) method is called, or shouldComponentUpdate(...) is called. If any of these happen, the component just calls its render() method to emit JSX code. There are no watchers inside the render() method. So, this explains the difference between how the recursive rendering problem is implemented in Angular and in React.

The Results 

All 3 approaches give the same results:

Final results

The first approach is the fastest to run since it doesn’t initialize a full-fledged component on every recursion step. The third approach doesn’t duplicate the path data in every node component.  

Conclusions

In this post I demonstrated 3 approaches to recursively render a deeply nested travel gallery in Angular. The third approach illustrates how the change detection mechanism works in Angular and how it differs from that of React. Never call methods directly from an Angular template!  

The code for all 3 approaches is here.



Source link

Ground Rules for Web Animations
Strategy

Ground Rules for Web Animations


Animations can make a site stand out. Or, they can just as easily kill the experience. When working with web animations, there are a few things that could go wrong like adding animations that serve no purpose, setting durations that are  too long or too quick, or not using right type of animation in the first place. Even if all of these things are done correctly, an animation  style may not feel good, especially if they are not in sync with other animations or in line with the overall personality of the site.

Another important thing to note is that not all digital experiences should share the exact same animations. A marketing website might need different animations than a product website or a mobile app. Although the same basic principles of motion apply for all, there’re some nuances based on content type and screen size. 

For example, say you want to make a boring form more exciting to fill out. You add some delightful animations in each step moving forward, but is that a good idea for a form you know a user needs to visit and fill often? Watching the same animations over and over could get annoying in that case.

Clearly, there are conditions and considerations that will serve animations well. In this article, we’ll discuss about adding animations into product websites. Let’s dig into that a bit and lay down some ground rules for working with them. Not so much a manifesto, but more like a baseline we can reference and sort of rally around.

First off, what’s a good situation for an animation?

When used well, an animation is almost like content — it provides context and has meaning that helps inform the user that something has happened and even what to expect next. Here are a few good situations where animation can do exactly that.

Transitioning UI blocks

This might be the most common use case for animations. When a UI block is moved from its original position, or is added or removed from the DOM, it’s a good idea to let users see that happen.

It’s easy to see the change with animation
…but it’s hard to figure out what changed without it.

Loading content

A loading animation is something we’ve all seen and encountered at some point in time! If not, a quick trip to CodePen shows you just how popular loading animations are. They’re ideal as placehholders for content, where users are not only given a hint at what to expect when the content loads, but confidence that something is being loaded at all.

Besides making the site feel fast, it also avoids janky content reflow, which can be super disorienting as elements render at different times.

Loading placeholders are best, of course, when you know the height of content blocks ahead of time.

Hinting

This is generally a one-time animation where the point is to give users a hint for where to look or what to do next. Some UIs are complex by nature. A little glow or ripple can help guide users through the process of completing a task or calling out a particular feature.

It doesn’t have to be all up in the user’s face. Instead, a little visual hint that informs without taking over the entire experience will do just fine.

Micro-interactions

Generally used on individual elements, micro-interactions give users instant visual feedback after performing an action. They instill confidence that a performed action has taken place and that something happened as a result — all while adding a little delight at the same time. 

These do not have to be fancy, like Twitter’s heart animation, but they totally should indicate some kind of feedback or response to the user’s action. Just check out how subtle — yet delightful — that is when a user does something as small as adding an item from one line to another:

It’s small, but that little bounce provides instant feedback to user’s action.
Um, ok, so what just happened? It’s hard to tell when there’s no response.

OK, so when should we avoid animations?

We’ve just seen handful of situations where animations make a lot of sense. Let’s spell out the opposite conditions where animations generally contribute very little or nothing to the user experience. In other words, they become noticeable for bad reasons and are probably best left out of the equation.

Route transitions

Yes, we usually don’t see these sorts of animations on product websites but it’s worth mentioning to understand why they don’t make sense. These transitions work better on mobile apps because of the small screen area. On desktop screens there’s much larger area to animate. To animate the whole content smoothly, you’ll require to set more duration than on mobile screen. This will simply annoy the users making them wait to see the content as they are already used to see instant content visibility on the web. And in the worst cases, route transitions can not only be distracting, but a severe accessibility concern when it comes to motion sensitivity.

On initial load of page content

You may do it in marketing websites when you want to educate users or move their focus  to a particular block. For product websites, it will be again annoying to see the same animation each time users navigates between pages.

When it’s unexpected

It’s a good idea to consider a user’s state of mind while they use a particular feature. Is visual feedback expected where the animation is being used? If not, it can confuse more than it helps.

For example, checkout this calculator app. There’s nothing new in the UI pattern when numbers are entered and calculations run. Users already know where to focus. There’s no point in making users wait before they can see results or surprise them with something that provides no additional meaning or benefit.

A snappy change without an animation is perfect in this case. The button hover and active states are more than enough.
A snappy change without an animation is perfect in this case. The button hover and active states are more than enough.

When you’re unsure how well it performs

It’s worth bearing in mind that not all devices, internet connections, and browsers are equal in the eyes of animation. Eric Bailey sums this up nicely in his deep-dive on the prefers-reduced-motion media query:

We also need to acknowledge that not every device that can access the web can also render animation, or render animation smoothly. When animation is used on a low-power or low quality device that “technically” supports it, the overall user experience suffers. Some people even deliberately seek this experience out as a feature.

The heading above that quote is a sage reminder: Animation is progressive enhancement. If we plan on using an animation — especially ones that threaten to dominate the experience — we’ve gotta at least consider a way to opt out of it and whether the experience still works without the animation. prefers-reduced-motion is the best place to start.

When the purpose isn’t clear

Lastly, I’d say don’t add animations wherever you’re not absolutely sure about the purpose it serves. Superfluous animation can be distracting and hurt more than it helps. This tweet from 2018 is still very true:

How long should an animation last?

The length of an animation is just as important as the type of animation being used. Wait too long, and the animation can appear to drag on. Go too fast, and the nice details of the animation can get lost (in best cases) or completely disorient the user (in worse cases).

So, how long should we set the duration of an animation? I’ll give you a classic answer: It depends.

The bigger the distance, generally the longer the duration

Animations (like the ones we looked at earlier) can be limited to a short duration. But if we’re taking about a massive transition where an object is traveling a long distance, we may feel it needs something a little longer to make sure things don’t move too fast. But avoid using duration longer than 400ms.

Check out this example. Notice how the content takes a little longer to transition because it has a greater distance to travel. But also notice that the it doesn’t have to last too long because the object that leaves fades into the object that enters, and the object that enters comes at a shorter distance rather than making it travel across the entire screen.

Goes to show that even big animations can be optimized in ways that make it feel shorter without getting lost in the mix.

Use a shorter duration when the user triggers the action

This is important and a common mistake. If the user already expects something to happen — and the focus is already clearly where it should be — then there’s no point in making the user wait seconds to complete what they already expect.

Instant reaction to what user is expecting
Making user wait…

On the other hand, if the change is automatically triggered by the system, a longer duration makes sense, as it will allow the user to catch up to speed with the change taking place. Think of tooltips or modals that are not triggered by the user do not require a their immediate attention.

Less distracting with subtle entrance
Too distracting with short animation duration

Enter and exit animations can have different durations 

Sometimes it makes sense to keep the animation for an object that is entering view a little faster than an animation for an object that is exiting, especially when the user is expecting to see that content change.

Take the previous example of dropdown menu. When a user clicks on it, they’d want to see the menu items right away — at least, I wouldn’t have to wait to see menu items. When the user clicks, let the submenu enter quickly and then smoothly leave when it’s dismissed so that it avoids distracting the user on the way out, when it’s no longer needed.

But this does not apply for large UI blocks. On larger blocks, for most cases, a duration longer than 200ms is required. In such cases, reversing the durations and letting a block exit faster than it entered ensures it won’t block the existing page view.

Doesn’t block the page view on exit
Blocks the page view on exit

Animation duration across the product should be in sync with each other and with the brand’s personality

I’ve came across many products where one feature has really nice animations and another is simply too quick, slow or lacks any animation at all. 

Even worse is when animations within the same feature aren’t in sync.

Notice how the sidebar animates when it enters view, but also how it is totally out of sync with the animation that changes the width of the main content. It feels unnatural when they aren’t in harmony.

That’s where having a style guide with thoughtful animation guidelines that can be used consistently across the experience can be a huge help.

How simple is too simple? Or how complex is too complex?

The complexity of an animation ought to be based on how frequently users are expected to encounter it, among the other things we’ve looked at so far. The more often users are expected to see it, the simpler the animation should be. This should override the previous rules of duration where necessary.

For example, the below animation would work in a main menu, but using the same staggering effect in drop-down menus across the product is just too much to take in. There is indeed a point of diminishing returns in animations, just as there is in economics.

But, hey, if this sort of complex animation is used sparingly in intentional instances, then it can be incredibly delightful!

But yes, you can be creative with the animations where there’s a decision pending at the user or while processing data. This makes waiting times more engaging, like when network breaks or a wrong passcode is submitted.

Which easing function should you use?

Ease? Ease in? Ease out? Ease in and out? Some cubic bezier curve?

The right easing adheres to the laws of physics. Disney’s principles of animation is the gold standard when it comes to that.

For enter animations, use bounce effect if you want immediate attention of the user, otherwise use a smooth acceleration (and deceleration, for that matter) that is incremental rather than linear. Bouncing should reflect gravity. Brandon Gregory’s post on natural-feeling animations provides all kinds of examples that fall in line with the laws of physics.

You can refer to this Gist by Adam Argyle for defining easings in CSS.

Lights, camera, and… intentional action!

Attention to detail is what separates outstanding animations from ordinary (or even straight up broken) ones. If you’re in the process of learning web animations or currently working on a project that calls for them, I sure hope this post can serve as a set of useful ground rules to help you get the most out of your work.

Apart from the rules, I’d also mention that good animations take time and practice. Sure, a lot of the stuff I covered here is somewhat anecdotal and based on personal experience, but that’s the result of developing an eye for animations after years of working with them. Learn, try, improve, and keep learning. Otherwise, you may end up with a collection of animations that deliver poor user experiences and even hurt the accessibility of your site.





Source link

r/webdev - [CSS] Remove Button style/function
Strategy

[CSS] Remove Button style/function : webdev


Hey fellow devs, I just started out in WebDev after some time with C#/Java/Games and I’m trying to learn a thing or two.

My problem is: How do I get rid of the black rounded border after clicking on an element?I tried overriding the ::selection, :active, :hover css classes with no success.

r/webdev - [CSS] Remove Button style/function

How do I get rid of the black border after clicking?

The way this table of buttons is set up is a js script that builds the whole thing, removes the “style” attribute and adds the appropriate css with classlist.add('cssClass')

What am I missing or what keywords are the things I have to search for?

Any advice is appreciated

EDIT:

The solution to this is to set

.class:focus { outline: none; }

Thanks u/-noveltyhero-



Source link

Dashboard in the Ionic web app
Strategy

Interactive Data Visualization in Ionic 5


Hi everyone!

In this tutorial, I’d like to show you how to create a simple yet powerful reporting app with a native look and feel using Ionic 5 and Flexmonster Pivot Table & Charts — a JavaScript pivot table component that integrates with React, Angular, and Vue. 

But first, let me do a quick reminder of what Ionic is and what benefits it can bring to web development. 

If you are a seasoned pro in Ionic, skip this section and jump straight to the tutorial. 

What Is Ionic Used for? 

Ionic is a framework that provides a toolkit for creating production-ready mobile apps and progressive web apps.

All you need is to use web technologies you got used to.

Using a single codebase, you can create and run an app on any platform. Besides, Ionic is framework-agnostic, meaning you can integrate it with any front-end framework. Most popular are React, Angular, and Vue (official integration is coming soon). 

Another plus is that you can access native device features with just a little bit of JavaScript. 

Besides, you can always rely on the community’s help – there are lots of plugins, starters, templates, and themes to help you keep moving forward. Using them in your projects is time-saving – no need to build every piece of functionality from scratch. 

Creating a Reporting App in Ionic

What will you get as a result?

After the tutorial completion, you’ll get an analytics reporting app running. You can deliver it to end-users as a tool for in-depth data analysis. The layout and design of the app will depend on your specific case. You can treat this tutorial as a general approach to building reporting software. 

Here’s a brief overview of features your project will be empowered with:

  • Composing reports with drag & drop 

  • Aggregating, grouping, filtering, and sorting data interactively 

  • Highlighting what matters most with formatting

  • Saving & exporting reports with a few clicks

And more!

Prerequisites

And a desire to create an awesome app!

Starting an Ionic Project

We’re going to use React as a front-end framework for the Ionic app. If you’d like to repeat the process in Angular, check out the links in the reference below.

Following the steps from the official guide, create a basic Ionic app. Skip this step if you already have an app. 

Next, add the Flexmonster React module:

 

Open index.tsx and import the styles of a pivot table control:

import 'flexmonster/flexmonster.css';

Open src/App.tsx and include the FlexmonsterReact package here:

import * as FlexmonsterReact from 'react-flexmonster';

Right there, create a report based on your data. I took the “Apple mobility trends” dataset from Kaggle and put the CSV file to the public/assets folder. Our report will show the average mobility values by months in different regions. 

Here, the mapping object is defined to prettify the captions of the fields and set their data types explicitly. 

Next, embed the pivot table component and set the previously defined report:

Run the app:

npm run start

Creating a Dashboard

Now you have a pivot table that shows the summarized data in your Ionic app. But what if you want to add more visualization elements to the web page?

Here’s where the concept of dashboard comes in handy. A dashboard usually consists of different data visualization components that show data from multiple angles and help answer the question that a data analyst is posing. 

Let’s create an interactive dashboard by adding one more element to the page – Pivot Charts

It can be done in the same way as for the pivot table. The only difference is that you need to turn on the chart mode using options

Here we composed a slightly different report that highlights other aspects of data:

Result

You’re all set!

Dashboard in the Ionic web app

Dashboard in the Ionic web app

Deploying Mobile

The next step is to deploy the app on a mobile platform of your choice. Check out recommendations and guidelines on deployment on the official Ionic website

Once you are done, let’s test the app on a mobile device using a device emulator of Android Studio or Xcode. 

Here’s how your mobile dashboard looks on iPhone 5/SE:

Excel app in Ionic mobile app

To style up the app, you can use the beautiful Ionic UI components

Useful Links



Source link

r/webdev - Help me find out what
Strategy

Help me find out what’s wrong with my CSS! : webdev


Can someone help me understand why my layout is breaking when I zoom in or out? I’ve tried numerous solutions posted around the web, but none of them work for me, including using em units instead of px in my css, and even adding bootstrap which broke the layout even more. I’m working on a small board game, and I think the problem might be with my positioning.

Here’s an image of how the board looks like when I zoom out

r/webdev - Help me find out what's wrong with my CSS!

Layout break

This is the HTML

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <meta name="description" content="">
    <meta name="keywords" content="">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
</head>

<body>
    <div class="container-fluid">

        <div class="brow1">
            <div id="tile_1" class="">1</div>
            <div id="tile_2" class="">2</div>
            <div id="tile_3" class="">3</div>
            <div id="tile_4" class="">4</div>
            <div id="tile_5" class="">5</div>
            <div id="tile_6" class="">6</div>
            <div id="tile_7" class="">7</div>
            <div id="tile_8" class="">8</div>
            <div id="tile_9" class="">9</div>
            <div id="tile_10" class="">10</div>
        </div>
        <div class="brow2">
            <div id="tile_11" class="">11</div>
            <div id="tile_12" class="">12</div>
            <div id="tile_13" class="">13</div>
            <div id="tile_14" class="">14</div>
            <div id="tile_15" class="">15</div>
        </div>
        <div class="brow3">
            <div id="tile_25" >25</div>
            <div id="tile_24" >24</div>
            <div id="tile_23" >23</div>
            <div id="tile_22" >22</div>
            <div id="tile_21" >21</div>
            <div id="tile_20" >20</div>
            <div id="tile_19" >19</div>
            <div id="tile_18" >18</div>
            <div id="tile_17" >17</div>
            <div id="tile_16" >16</div>
        </div>
        <div class="brow4">
            <div id="tile_30" >30</div>
            <div id="tile_29" >29</div>
            <div id="tile_28" >28</div>
            <div id="tile_27" >27</div>
            <div id="tile_26" >26</div>
        </div>
    </div>
</body>
<link rel="stylesheet" media="screen and (max-width: 1920px)" href="style.css">
</html>

Here’s the CSS

.container-fluid{
    min-width: 1366px;
    max-width: 2048px;
    margin: 0px auto; 
    width: 100%;
}

.brow1 {
    position: fixed;
    top: 3.125em;
    left: 29.375em;
    float: right;
}

.brow1>div {
    border-right:3px solid #328adb;
    display: inline-block;
    width: 4rem;
    height: 4rem;
    justify-content: center;
    text-align: center;
    background: rgba(255, 255, 255, 0.739);
    position:relative;
}

.brow2 {
    position: fixed;
    top: 3.125em;
    right: 3.438em;
}

.brow2>div {
    border-bottom:0.188em solid #328adb;
    margin-bottom: 0.250em;
    display: block;
    width: 4rem;
    height: 4rem;
    justify-content: center;
    text-align: center;
    background: rgba(255, 255, 255, 0.739);
    position:relative;
}

.brow3 {
    position: fixed;
    bottom: 8.125em;
    right: 3.438em;
}

.brow3>div {
    border-left:3px solid #328adb;
    display: inline-block;
    width: 4rem;
    height: 4rem;
    justify-content: center;
    text-align: center;
    background: rgba(255, 255, 255, 0.739);
    position:relative;
}

.brow4 {
    position: fixed;
    top: 7.813em;
    left: 29.375em;
}

.brow4>div {
    border-top:0.188em solid #328adb;
    margin-bottom: 0.313em;
    display: block;
    width: 4rem;
    height: 4rem;
    justify-content: center;
    text-align: center;
    background: rgba(255, 255, 255, 0.739);
    position:relative;
}

Thank you!



Source link