CSS3 Animation for Sliding AngularJS Material from Left to Right

I am attempting to "convert" this AngularJS slide left / right example into an AngularJS Material version.

The latter URL includes the following code snippets:

HTML snippet:

<div ng-controller="ExampleController" ng-app="switchExample">
  <!--<select ng-model="slide" ng-options="item as item.name for item in slides">
  </select>-->
  <code>slide={{slide}}</code>
  <code>moveToLeft={{mtl}}</code>
  <md-button ng-click="prev()"><</md-button>
  <md-button ng-click="next()">></md-button>
  <div class="">
      <div class="ngSwitchItem" ng-if="slide.name == 'first'" ng-class="{'moveToLeft' : mtl}">
        <div class="firstPage page" md-swipe-left="selectPage(1)">
          first
        </div>
      </div>
      <div class="ngSwitchItem" ng-if="slide.name == 'second'" ng-class="{'moveToLeft' : mtl}">
        <div class="secondPage page" md-swipe-right="selectPage(0)" md-swipe-left="selectPage(2)">
        second
        </div>
      </div>
      <div class="ngSwitchItem" ng-if="slide.name == 'third'" ng-class="{'moveToLeft' : mtl}">
        <div class="thirdPage page" md-swipe-right="selectPage(1)" md-swipe-left="selectPage(3)">
        third
        </div>
      </div>
      <div class="ngSwitchItem" ng-if="slide.name == 'fourth'" ng-class="{'moveToLeft' : mtl}">
        <div class="fourthPage page" md-swipe-right="selectPage(2)">
        fourth
        </div>
      </div>
  </div>
</div>

JavaScript function

(function(angular) {
  'use strict';
angular.module('switchExample', ['ngMaterial', 'ngAnimate'])
  .controller('ExampleController', ['$scope', function($scope) {

    $scope.slides = [
      { index: 0, name: 'first' }, 
      { index: 1, name: 'second' }, 
      { index: 2, name: 'third' }, 
      { index: 3, name: 'fourth' }
    ];
    $scope.selectPage = selectPage;
    /**
    * Initialize with the first page opened
    */
    $scope.slide = $scope.slides[0];

    $scope.prev = () => {
      if ($scope.slide.index > 0) {
        selectPage($scope.slide.index - 1);
      }
    }

    $scope.next = () => {
      if ($scope.slide.index < 3) {
        selectPage($scope.slide.index + 1);
      }
    }

    /**
    * @name selectPage
    * @desc Updates the displayed page based on the selected index
    * @param indexSelected the index of the page to be displayed
    */
    function selectPage(indexSelected) {
        if ($scope.slides[indexSelected].index > $scope.slide.index) {
            $scope.mtl = false;
        } else {
            $scope.mtl = true;
        }
        $scope.slide = $scope.slides[indexSelected];
    }
  }]);
})(window.angular);

CSS styling

body {
    overflow-x: hidden;
}

.ngSwitchItem {
    position: absolute;
    top: 50px;
    bottom: 0;
    right: 0;
    left: 0;

    animation-duration: 10.30s;
    animation-timing-function: ease-in-out;
    -webkit-animation-duration: 10.30s;
    -webkit-animation-timing-function: ease-in-out;

}

.page {
    position: inherit;
    top: 0;
    right: inherit;
    bottom: inherit;
    left: inherit;
}

.firstPage {
    background-color: blue;
}

.secondPage {
    background-color: red;
}

.thirdPage {
    background-color: green;
}

.fourthPage {
    background-color: yellow;
}

/* Slide from the right when entering */
.ngSwitchItem.ng-enter {
    animation-name: slideFromRight;
    -webkit-animation-name: slideFromRight;
}
/* When entering and moveToLeft is true, slide from left to right */
.ngSwitchItem.moveToLeft.ng-enter {
    animation-name: slideFromLeft;
    -webkit-animation-name: slideFromLeft;
}
/* When leaving, slide to the left from the left corner */
.ngSwitchItem.ng-leave {
    animation-name: slideFromLeft;
    animation-direction: reverse;
    -webkit-animation-name: slideFromLeft;
    -webkit-animation-direction: reverse;
}
/* When leaving, slide to the right from the left corner */
.ngSwitchItem.moveToLeft.ng-leave {
    animation-name: slideFromRight;
    animation-direction: reverse;
    -webkit-animation-name: slideFromRight;
    -webkit-animation-direction: reverse;
}

@keyframes slideFromRight {
    0% {
        transform: translateX(100%);
    }

    100% {
        transform: translateX(0);
    }
}

@keyframes slideFromLeft {
    0% {
        transform: translateX(-100%);
    }

    100% {
        transform: translateX(0);
    }
}

@-webkit-keyframes slideFromRight {
    0% {
        -webkit-transform: translateX(100%);
    }

    100% {
        -webkit-transform: translateX(0);
    }
}

@-webkit-keyframes slideFromLeft {
    0% {
        -webkit-transform: translateX(-100%);
    }

    100% {
        -webkit-transform: translateX(0);
    }
}

Upon testing, it appears that the second example behaves differently compared to the first one when changing slide directions. For instance:

  1. Sliding left in the first example loads the second slide with the correct animation
  2. However, sliding right in the second example results in the first slide appearing from the middle of the content instead of the expected behavior of it starting its appearance from the left side while the second slide disappears to the right side. In some cases, a white slide is shown from the right side instead of the proper animations taking place.

Please note that I purposely delayed the animations in the second example to highlight these undesired effects clearly.

Answer №1

Upon conducting further research, I was able to locate the root of the problem - it appears that I need to delay the change in scope variable for the next tick to allow ng-class to work its "magic".

To put it simply, the addition of the following code resolved the issue:

$timeout(() => {
  $scope.slide = $scope.slides[indexSelected];
}, 0)

Feel free to check out the updated example along with the code snippet below:

JavaScript Code

(function(angular) {
  'use strict';
angular.module('switchExample', ['ngMaterial', 'ngAnimate'])
  .controller('ExampleController', ['$scope', '$timeout', function($scope, $timeout) {

    $scope.slides = [
      { index: 0, name: 'first' }, 
      { index: 1, name: 'second' }, 
      { index: 2, name: 'third' }, 
      { index: 3, name: 'fourth' }
    ];
    $scope.selectPage = selectPage;
    /**
    * Initialize with the first page opened
    */
    $scope.slide = $scope.slides[0];

    $scope.prev = () => {
      if ($scope.slide.index > 0) {
        selectPage($scope.slide.index - 1);
      }
    }

    $scope.next = () => {
      if ($scope.slide.index < 3) {
        selectPage($scope.slide.index + 1);
      }
    }

    /**
    * @name selectPage
    * @desc The function that includes the page of the indexSelected
    * @param indexSelected the index of the page to be included
    */
    function selectPage(indexSelected) {
        if ($scope.slides[indexSelected].index > $scope.slide.index) {
            $scope.mtl = false;
        } else {
            $scope.mtl = true;
        }
      // this will move a scope variable change to the next tick, 
      // hence will give time $scope.mtl to be handled by ng-class
      $timeout(() => {
        $scope.slide = $scope.slides[indexSelected];
      }, 0)

    }
  }]);
})(window.angular);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is Bootstrap CSS Carousel malfunctioning following a float adjustment?

Currently, I am trying to implement a carousel in bootstrap, but I am facing two significant issues. The alignment of the carousel is vertical instead of horizontal (my div elements are stacking downwards). When I apply the float: left property, the carou ...

In Internet Explorer 7, the combination of having a hasLayout property along with setting the position to relative,

Issue: Encountering a challenge in IE7 with a div containing a gradient and a flyout menu on hover. Although it may seem simple, applying position:relative to the container for accurate menu positioning conflicts with the filter/hasLayout combination. Ch ...

How to Eliminate Lower Borders from DataGrid Component in Material UI (mui)

I've been trying to customize the spacing between rows in a MUI Data Grid Component by overriding the default bottom border, but haven't had much success. I've experimented with different approaches such as using a theme override, adding a c ...

Linking model attribute to checkbox in AngularJs

Currently, I am working on assigning tags during post creation. For this purpose, I have set up a Post model with the following structure: var mongoose = require('mongoose'); var PostsSchema = { title: String, content: String, poste ...

A pair of boxes sitting next to each other, both occupying 50% of the space but slightly longer in length and not aligned on the same level

My goal is to have two side-by-side boxes that fill the entire width of the screen. However, I'm facing an issue where each box exceeds 50% width by about 10 pixels. What could be causing this discrepancy? #sides { padding-top: 40px; padding- ...

Setting the height of both the body and html elements to 100% will result in the

Although this question has been previously asked, the solutions I came across are not effective. Here is the code in question: body, html { height: 100%; background-color: white; } body { margin: 0; padding: 0; } The issue I am facing is ...

Incorporating a Unique Identifier to a Marker in GMaps.js

Instead of using the default Google Maps, I decided to use a package called GMaps.js, which is designed to simplify the process. I am currently trying to figure out how to assign an ID to a Marker in GMap.js. Here is what I have so far: map.addMarker ...

Issue: The property 'top' cannot be read as it is null

I'm trying to access the top of my footer, but I keep encountering this error message: Cannot read property 'top' of null Here is the HTML code: <footer class="footer" role="complementary" id="myfooter"> </footer> And in jQuer ...

Unleashing the power of real-time communication with XMPP using AngularJS

I am currently working on transitioning the basic XMPP setup using Strophe and JavaScript to AngularJS. .controller('loginCtrl', function(xmppAuth) { xmppAuth.auth(login, password); }) and in service: .service('xmppAuth', f ...

Unable to horizontally center ul element within Materialize navigation content

Struggling to center nav-content by using the center option Hoping for it to have this appearance. Unfortunately, applying it directly to the ul attribute doesn't yield desired results. Instead, it ends up looking like this. This is the code snipp ...

AngularJS form submission with Ajax requiring a double click to successfully submit the form

I need to perform the following activities on my HTML page: User inputs email and password for registration Form is sent to Controller when user clicks Submit Controller uses AJAX to create JSON request to RESTful Server and receives response from server ...

Is it possible to add a gap between shadowed div elements?

I am attempting to create 3 divs in a single row. Each div is divided into two parts, one with an image and the other with three lines of text. The divs have a box-shadow style applied to them. However, I am facing issues with spacing between the divs. W ...

Deactivate Link Using CSS while Allowing Title to be Functional

Is there a way to enable the link in CSS while still showing the title? Take a look at my code: CSS and HTML Code: .disabledLink { pointer-events: none; opacity: 0.6; cursor: default; } <a href="www.google.com" class="disableLink" title="M ...

Exploring the power of Foundation For Apps and Angular by seamlessly displaying dynamic data sourced from

I'm currently working with Foundation for Apps, a framework that incorporates elements of AngularJS. My goal is to display the content from a local JSON file by accessing it through a controller and rendering the results as 'cards'. Addition ...

Can the outcomes be showcased again upon revisiting a page?

Whenever I navigate away from and return to my filter table/search page, the results vanish. I'm looking for a way to preserve the results without reloading the page. Essentially, I want the page to remain as it was originally, with the search results ...

Dynamic design with consistent spacing that increases in harmony with each row

My challenge is to maintain the left alignment of elements in a container that can increase or decrease in width. If the container size increases, the first element from the next row should move back one row and align on the right side if there is enough s ...

Passing dynamic scope from Angular to a directive is a seamless process

I am working with a directive that retrieves an attribute value from an http call in the following manner: Controller app.controller("HomeController", function($scope){ $http.get("/api/source").then(function(res){ $scope.info = res.data }); }); ...

Set the datepicker with the window positioned to the right side

In my current project, I am utilizing Angular 13, Bootstrap 5, and ngx-bootstrap-fix-datepicker version 5. "bootstrap": "^5.1.3", "ngx-bootstrap": "^8.0.0", "ngx-bootstrap-fix-datepicker": "^5.6.8" ...

Unexpected Object Binding in Angular Select List Causing Confusion

It has crossed my mind that maybe I am approaching this in the wrong way, but here is the problem at hand. My Select List is set up in the following manner: <select name="{{ measure.Name }}_MeasureId" ng-model="CompleteDataSetViewModel.AnnualRecor ...

The page displays a pair of vertical scrolling bars

My webpage is displaying two scrollbars on the right side of the browser, but I only want one scrollbar. Can anyone help me fix this issue? Thank you for any assistance. html, body { margin: 0; background-image: url("images/background.png"); ...