Is there a way to get the current used language in a controller (without $translateProvider)?
Couldn't find anything in the $translate service.
$translate.use() is a getter and setter.
See this demo found in links of docs:
http://jsfiddle.net/PascalPrecht/eUGWJ/7/
$translate.use() is the way to go. Also, when an asynchronous loader is executed, you might wanna use $translate.proposedLanguage() which returns the language key of the language that is currently loaded but not finished loaded yet.
When using angular-translate-loader-static-files I have noticed that $translate.proposedLanguage() returned undefined when using the default language while $translate.use() always returned the proposed language.
Therefore I fixed it by using:
var currentLang = $translate.proposedLanguage() || $translate.use();
$translate.use() seems not to work on initial load of the app, to get last selected language from storage: $translate.storage().get( $translate.storageKey() )
or just
$translate.proposedLanguage();
The $translate service has a method called preferredLanguage() that return what you want. The return of this function is the string of the language, like 'en'.
Here i wrote you an example:
angular.module('traslateApp').controller('myController', ['$scope', '$translate', function($scope,$translate){
$scope.changeLanguage = function (langKey) {
$translate.use(langKey);
};
$scope.getCurrentLanguage = function () {
$translate.preferredLanguage();
};
}])
translate.currentLang is used to check the current selected language in i18n
I think this is the better way to determine the language -
$window.navigator.language || $window.navigator.userLanguage
Maybe is not related but could be useful. In angular2+ the way to access to the current language is
...
import { TranslateService } from '#ngx-translate/core';
export class MyComponent implements OnInit {
constructor(private translate: TranslateService) {}
ngOnInit() {
translate.use('it');
const currentLang = this.translate.currentLang;
}
}
import { TranslateService } from '#ngx-translate/core';
export class MyComponent implements OnInit {
constructor(private translate: TranslateService)
{
translate.setDefaultLang('en');
}
Related
I have a child service that I want to extend from a parent service using the extends keyword. I'm having some trouble injecting another service MyService into the child service.
export class ParentService {
constructor($http) {}
get() {
this.$http.get('/someUrl').then(res => res.data);
}
}
export class ChildService extends ParentService {
constructor($http, private MyService) {
super($http);
}
get() {
const data = super.get();
return this.MyService.cleanData(data);
}
}
For some reason MyService is coming back as undefined in the ChildService, and I can only assume something is going wrong with the DI. If I remove the extends keyword however, MyService works as expected.
Any idea what might be going on here. Any help is appreciated. Thanks in advance!
Try renaming the get() methods within the ParentService and ChildService to anything else.
get is a keyword/binding-syntax that binds an object property to a function that is called when that property is looked up. The compiler is expecting a property or function name after the get and may be getting tripped up. Even in Plunkr get is highlighted by the IDE indicating a reserved word/syntax.
get could be used like this with ES6 classes:
class Todo {
constructor(task) {
this.task = task;
}
get task() {
return this.task.toUpperCase();
}
}
The get syntax binds an object property to a function that will be
called when that property is looked up.
Try changing get to getData or whatever you need.
export class ParentService {
constructor($http) {}
getData() {
return this.$http.get('/someUrl');
}
}
export class ChildService extends ParentService {
constructor($http, private MyService) {
super($http);
}
getData() {
return super.getData()
.then(data => this.MyService.cleanData(data))
.catch(error => console.log(error));
}
}
Here is a plunker demonstrating the functionality at a very basic level including a ParentService, ChildService, and a MyService, with MyService being injected into ChildService and ChildService extending ParentService. A console.log() is being executed in this example within the constructor() of the child to show that DI is occurring properly.
Hopefully this helps!
I know there are similar questions, but somehow they all have different code and i cant seem to find something that answers my specific problem, im sorry.
Im following several exmaples, and i got here:
This is my soon-to-be map service (maps.service.js):
import angular from 'angular'
import angularConfig from '../angularConfig/angularConfig'
export default class Maps {
initializeMap (element, options){
return new Promise(function(resolve){
return resolve(new google.maps.Map(document.getElementById(element), options))
})
}
}
Maps.$inject = ['$http']
angular.module(Maps, [])
.service('maps.service', Maps)
You can see its a simple class with a method inside.
At the bottom based on several examples i placed a call to angular.service, gave it a name and used the class i created. I think this is wrong, but i dont know why. I also dont know if thats the correct way to inject a service i need from angular into it.
Then, in order to consume this service i have a small controller (catalog.controller.js):
// import mapService from '../../common/maps/maps.service'
class catalogController {
constructor($scope, mapsService) {
this.$scope = $scope
}
$onInit () {
// map init
mapService.initializeMap(param1, param2)
.then(() => {
console.log('it worked!!')
})
}
}
catalogController.$inject = ['$scope']
export default catalogController;
The problem is no matter how i write the code in the service, i always end up with an error when i try to use it, when i inspect mapService to see what i has inside, the function is not there.
I tried importing it and passing it as a parameter to the constructor, i tried with different ways i found to create the service, but i cant make it work, everyone seems to be using something different.
Both this files are inside a folder named 'catalog', outside this folder i have this file:
import angular from 'angular'
import catalog from './catalog/catalog'
let componentModule = angular.module('app.components', [
catalog
])
.name
export default componentModule
which is in turn used by another file. This whole structure works, as i have things working already with controllers and views. My only problem is how to create and use a service.
Any help will be appreciated, as i have already spent many days on this!
I can provide more details if needed.
Thank you :)
According to DI, do some changes:
Maps Service:
import angular from 'angular'
import angularConfig from '../angularConfig/angularConfig'
export default class Maps {
constructor($http){}
initializeMap (element, options){
return new Promise(function(resolve){
return resolve(new google.maps.Map(document.getElementById(element), options))
})
}
}
Maps.$inject = ['$http']
angular.module(Maps, [])
.service('maps.service', Maps)
catalogController
class catalogController {
constructor($scope, mapsService) {}
$onInit () {
// map init
this.mapService.initializeMap(param1, param2)
.then(() => {
console.log('it worked!!')
})
}
}
catalogController.$inject = ['$scope', 'mapsService']
export default catalogController;
PS: Here is a good example: https://github.com/FountainJS/generator-fountain-angular1
Background:
On a project I am working on, we've switched from using AngularJS (1.6.2) with JavaScript, to TypeScript 2.1.5.
We have a decorator applied to the $exceptionHandler service that causes JavaScript exceptions to make a call to a common API that send the development team an e-mail; in this way, we can easily see what front-end errors our end-users are encountering in the wild.
Problem:
I recently converted this decorator from JavaScript, to TypeScript. When I try to run the application, I encounter a whitescreen of nothing. After much debugging I discovered that the issue is because AngularJS expects the $provide.decorator to pass a function along with a list of dependencies. However, an object is instead being observed, and thus forcing Angular to fail-safe.
I diagnosed the problem by setting breakpoints inside of angular.js itself; it specifically will fail on line 4809 (inside of function createInternalInjector(cache, factory)) due to a thrown, unhandled JavaScript exception, but the part that's actually responsible for the failure is line 4854, inside of function invoke(fn, self, locals, serviceName). The reason it fails, is because the dependencies passed come across as ['$delegate', '$injector',]; the function is missing from this set.
Lastly, one thing I considered doing was simply defining a JavaScript function in the class code. This does not work in my case for two reasons. First, in our ts.config, we have noImplicitAny set to true; functions are implicitly of the any type. Additionally, TypeScript itself appears not to recognize function as a keyword, and instead tries and fails to compile it as a symbol on class ExceptionHandler.
TypeScript Exception Handler:
export class ExceptionHandler {
public constructor(
$provide: ng.auto.IProviderService
) {
$provide.decorator('$exceptionHandler`, [
'$delegate',
'$injector',
this.dispatchErrorEmail
]);
}
public dispatchErrorEmail(
$delegate: ng.IExceptionHandlerService,
$injector: ng.auto.IInjectorService
): (exception: any, cause: any) => void {
return (exception: any, cause: any) => {
// First, execute the default implementation.
$delegate(exception, cause);
// Get our Web Data Service, an $http wrapper, injected...
let webDataSvc: WebDataSvc = $injector.get<WebDataSvc>('webDataSvc');
// Tell the server to dispatch an email to the dev team.
let args: Object = {
'exception': exception
};
webDataSvc.get('/api/common/errorNotification', args);
};
}
}
angular.module('app').config(['$provide', ExceptionHandler]);
Original JS:
(function () {
'use strict';
angular.module('app').config(['$provide', decorateExceptionHandler]);
function decorateExceptionHandler($provide) {
$provide.decorator('$exceptionHandler', ['$delegate', '$injector', dispatchErrorEmail]);
}
function dispatchErrorEmail($delegate, $injector) {
return function (exception, cause) {
// Execute default implementation.
$delegate(exception, cause);
var webDataSvc = $injector.get('webDataSvc');
var args = {
'exception': exception,
};
webDataSvc.get('/api/common/ErrorNotification', args);
};
}
})();
Questions:
1. In what way can I rewrite the TypeScript Exception Handler to be properly picked up by AngularJS?
2. If I can't, is this an AngularJS bug that needs to be escalated? I know for a fact I'm not the only person using AngularJS with TypeScript; being unable to decorate a service due to language choice seems like a pretty major problem.
Converting everything to classes isn't the purpose of TS, there's no use for classes here. JS code is supposed to be augmented with types and probably be enhanced with $inject annotation.
angular.module('app').config(decorateExceptionHandler);
decorateExceptionHandler.$inject = ['$provide'];
export function decorateExceptionHandler($provide: ng.auto.IProviderService) {
$provide.decorator('$exceptionHandler', dispatchErrorEmail);
}
dispatchErrorEmail.$inject = ['$delegate', '$injector'];
export function dispatchErrorEmail(
$delegate: ng.IExceptionHandlerService,
$injector: ng.auto.IInjectorService
): (exception: any, cause: any) => void { ... }
config expects a regular function, not a constructor. And the reason why the original TS code fails is that ExceptionHandler isn't called with new, thus this is not an object, and this.dispatchErrorEmail is not a function.
Here's another way to do it using TypeScript namespaces. It feels a little cleaner to me, keeping the exception extension functions isolated, and is a nice conceptually coming from something like C#.
exception.module.ts
import * as angular from 'angular';
import { LoggerModule } from '../logging/logger.module';
import { ExceptionExtension } from './exception.handler';
export const ExceptionModule = angular.module('app.common.exception', [LoggerModule])
.config(ExceptionExtension.Configure)
.name;
exception.handler.ts
import { ILoggerService } from '../logging/logger.service';
export namespace ExceptionExtension {
export const ExtendExceptionHandler = ($delegate: ng.IExceptionHandlerService, logger: ILoggerService) => {
return function (exception: Error, cause?: string): void {
$delegate(exception, cause);
logger.error(exception.message, "Uncaught Exception", cause ? cause : "");
}
};
ExtendExceptionHandler.$inject = ['$delegate', 'ILoggerService'];
export const Configure = ($provide: ng.auto.IProvideService) => {
$provide.decorator('$exceptionHandler', ExtendExceptionHandler);
};
Configure.$inject = ['$provide'];
}
So I'm using
https://github.com/AngularClass/NG6-starter
with
https://github.com/Gillespie59/eslint-plugin-angular
I've got this simple class service
const auth = {
account: 'api/account'
};
class AuthService{
constructor($http) {
'ngInject';
this.http = $http;
}
account(){
return this.http.get(auth.account)
.then(function(response) {
var account = response.data;
return account;
});
}
}
export default AuthService;
if in the module index I do like
import AuthService from './auth.service';
.service('AuthService',AuthService)
and it seems good to me it's a class
so I don't understand why on earth
eslint-plugin-angular point me out
You should prefer the factory() method instead of service()
but on the other hand I can't use a factory it's a class
not a plain object !
I don't really understand the point.
Is there anyone out of there could me explain the topic
please ? May be I miss something.
Thanks in advance.
I'm writing an factory as a Typescript class and instantiating it with new FactoryName() when needed.
I'm getting it working as a factory by doing this: .factory('FactoryName', function() { return FactoryName; }) and it works great, but now I need to inject another factory I've made outside of Typescript into it without polluting the constructor call. Is that possible?
It is
app.factory('FactoryName', ['...', (...deps) => new FactoryName(...deps)]);
Since anonymous functions don't play well with $inject annotation, array annotation suits the case better.
I found a workaround:
export function FactoryName(injectedService1, injectedService2) {
return class FactoryClass {
constructor() {
let test = injectedService1.testFunction();
}
}
}
app.factory('FactoryName', FactoryName)