0

I am trying to build custom filter, that will change value for datetime that I have in UTC to user's timezone.

Since I am new to angularJs, I am not sure what should I do and where to register filter.

I have created filter as separated file named clientTime.js:

export default function(startDateTimeString) {

    let localTime  = this.$rootscope.momentTimezone.utc(startDateTimeString).toDate();
    localTime = this.$rootscope.momentTimezone(localTime).format("YYYY-MM-DD HH:mm");

    return localTime;
}

As an argument to a function I am passing startDateTimeString, which is a string value of date-time in this format: 'YYYY-MM-DD HH:mm'

In my HTML I have used filter like this:

<tr st-select-row="row" st-select-mode="multiple" ng-repeat="row in dashCtrl.upcomingSessionsDisplay" ng-switch on="row.status"
    ng-click="dashCtrl.handleClickOnUpcomingSessions(row)" title="{{dashCtrl.tooltip(row)}}">
    <td>{{row.locationName}}</td>
    <td>{{row.startDateTimeString | clientTime}}</td>
</tr>

I have app.js where I am registering all components such as: services, interceptor, etc. So I figure it out that I should register filter there as well.

I have import filter like all other components:

import toastr from "toastr";
import _ from "underscore";
import momentTimezone from "moment-timezone";
import Components from "./components";
import Directives from "./shared/directives";
import Constants from "./shared/constants";
import Services from "./shared/services";
import Controllers from "./shared/controllers";
import AuthenticationInterceptor from "./shared/interceptors/AuthenticationInterceptor";
import ClientTime from "./shared/filters/clientTime";

And register it with the name 'clientTime':

angular
    .module("examino.main", ["ui.router", "smart-table", "ui.bootstrap", "ui.tree", Directives, Components, Constants, Services, Controllers])

    .run(function($rootScope, $state, AuthenticationService) {
        $rootScope._ = _;
        $rootScope.momentTimezone = momentTimezone;

        // register listener to watch route changes
        $rootScope.$on("$stateChangeStart", function(event, toState, params) {
            let goToStateName = "login";
            let isAccessTestSessionRoute = toState.name == "testEnv" || toState.name == "testEnv.dashboard" || toState.name == "sessionExpired";
            if(toState.name !== goToStateName && !AuthenticationService.isAuthenticated() && !isAccessTestSessionRoute) {
                event.preventDefault();
                $state.go(goToStateName);
            }

            if(toState.redirectTo) {
                event.preventDefault();
                $state.go(toState.redirectTo, params);
            }
        });
    })

    .config(function($urlRouterProvider, $locationProvider, $httpProvider) {
        $locationProvider.html5Mode(true);

        $urlRouterProvider.otherwise("/login");

        $httpProvider.interceptors.push("AuthenticationInterceptor");
    })
    .filter("clientTime", ClientTime)

    .service("AuthenticationInterceptor", AuthenticationInterceptor);

angular.bootstrap(document, ["examino.main"]);

//set toastr options
toastr.options = {
    positionClass: "toast-top-full-width"
};

I was pretty sure that this will work, but I get this error:

> vendor.js:26519 Error: [$injector:unpr] Unknown provider:
> startDateTimeStringProvider <- startDateTimeString <- clientTimeFilter
> http://errors.angularjs.org/1.5.8/$injector/unpr?p0=startDateTimeStringProvider%20%3C-%20startDateTimeString%20%3C-%20clientTimeFilter
>     at vendor.js:12667
>     at vendor.js:17110
>     at Object.getService [as get] (vendor.js:17263)
>     at vendor.js:17115
>     at getService (vendor.js:17263)
>     at injectionArgs (vendor.js:17287)
>     at Object.invoke (vendor.js:17309)
>     at Object.enforcedReturnValue [as $get] (vendor.js:17156)
>     at Object.invoke (vendor.js:17317)
>     at vendor.js:17116

Now I completely understand what is the problem, I guess that angular do not understand dependency for filter. But I am not sure what is the solution for this. I was starting from the idea that filter is similar to service or interceptor in a way that it is still an anonymous function, so I was thinking that this is the way for defining it. Can somebody share their experience with creating filters and possible solution to dependency problems?

2 Answers 2

1

The problem lies in HOW you are defining your filter. The 'angular.filter' expects a filter factory function, according to the documentation (Writing your own filter is very easy: just register a new filter factory function with your module - https://docs.angularjs.org/guide/filter).

So, your clientTime.js should be

export default function() {
  return function(startDateTimeString) {

    let localTime  = this.$rootscope.momentTimezone.utc(startDateTimeString).toDate();
    localTime = this.$rootscope.momentTimezone(localTime).format("YYYY-MM-DD HH:mm");

    return localTime;
  }
}

As you can see, the module now exports a function that returns your filtering function. Now it should work.

Sign up to request clarification or add additional context in comments.

4 Comments

Yeah, you were right. Now I have other problem, $rootscope is not recognized and I was expecting that one to happened. I will have to find a way to pass $rootscope to filter, but that is a whole other question and problem. Thanks for helping out. @igor.araujo
You should inject $rootScope on your filter factory function: export default function($rootScope){ ... } Do not forget to remove the 'this' variable from the filter code
that was the first thing I've did but it doesn't work. When I remove 'this' it says that $rootscope is not defined. Do I maybe need to do something like this.$rootscope = $rootscope? But I thing that that wont help as well... @ivan.araujo
@ivan.araujo my mistake, wrong spelling :/ it works. Thanks once again! :)
0

I didn't used filters that much, but for all I remember, you need to create a filter component like so

angular.module('yourModule')
    .filter('clientTime', function() {
        // Your code
    });

And I didn't see it in your post. Maybe this is why it doesn't work ?

2 Comments

Hello, thanks for responding. I saw that way as well, but I guess it is a way to create filter inside app.js and I wanted to make it in a separated file, that's why I am missing that code. @trichetriche
Well you don't need to put everything in "app.js" as you said. I have like 30 to 40 JS files in my project, all containing a single component (controller, service, factory, constants, config ...) All you need to do is create a separated file, put your JS tag in your index.html file, and put your filter in the separated file. But you do need to do as stated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.