Angular Translate works great as a filter in the view.
I am using angular-translate-loader-static-files with external files like locale-en.json etc.
The problem is when I try to do something like this:
var placeholder = $translate('placeholder.NAME')
.then(function (translatedValue) {
return translatedValue;
});
I always get a promise back, and in the UI it shows as {} instead of the word NAME for english etc.
What is the correct way to translate in JS using angular-translate?
EDIT:
Tried this and got the following result (still not solved)
var placeholder = '';
$translate('placeholder.NAME').then(function (translatedValue) {
console.log(translatedValue);
placeholder = translatedValue;
}, function(err){
console.log(err); // returns placeholder.NAME
});
console.log(placeholder); // returns empty string
var placeholder = '';
$translate('placeholder.NAME').then(function (translatedValue) {
placeholder = translatedValue;
});
I'd recommend to keep your controller free from translation logic and translate your strings directly inside your view like this:
<h1>{{ 'TITLE.HELLO_WORLD' | translate }}</h1>
You can use instant function to get the value without the promise:
var translation = $translate.instant('placeholder.NAME');
However, this does not wait for the translation files to get loaded. You should make sure you are calling this after translation files are loaded.
From the website http://angular-translate.github.io/docs/#/guide/03_using-translate-service635
app.controller('Ctrl', ['$scope', '$translate', function ($scope, $translate) {
$translate(['HEADLINE', 'PARAGRAPH', 'NAMESPACE.PARAGRAPH']).then(function (translations) {
$scope.headline = translations.HEADLINE;
$scope.paragraph = translations.PARAGRAPH;
$scope.namespaced_paragraph = translations['NAMESPACE.PARAGRAPH'];
});
}]);
Related
Iam trying to create a custom filter to filter matching array of values in angularjs. Array Structure below
["tag1","tag2"]
Now I need to filter all objs having tags matching id1,id2.. Below is the filter I have tried
var autoFilter = angular.module("autoFilters",[]);
autoFilter.filter('arrayData', function (){
return function(){
return ["id1","id2"];
}
//$scope.arrayValues = ["id1","id2"];
});
and UI code below
<li style="cursor:pointer" ng-cloak class="list-group-item" ng-repeat="values in suggestionResults | arrayData">{{values.id}} -- {{values.title}}</li>
But Data is not showing up. Can you help me out where Iam doing wrong. Plunker Code available below
plunker here
see the code below :) This is not the best approach in my opinion and will definitely have some performance issue with larger lists, but it does the work (now I used indexOf(2) but there you can pass any truthy/falsy argument)
var autoFilter = angular.module("autoFilters",[]);
autoFilter.controller("filterController",['$scope','$http', function ($scope,$http) {
$scope.searchSuggest = function(){
//$http({method: 'GET', url: 'json/searchSuggestions.json'}).success(function(data) {
$http.get("assets.json").then(function(response) {
//var str = JSON.stringify(response);
//var arr = JSON.parse(str);
$scope.suggestionResult = response.data;
console.log($scope.suggestionResult);
//$scope.arrayData = ["asset_types:document/data_sheet","asset_types:document/brochure"];
}).catch(function activateError(error) {
alert('An error happened');
});
}
$scope.showProduct = function(){
}
}]);
autoFilter.filter('arrayData', function (){
return function(data){
// if you are using jQuery you can simply return $.grep(data, function(d){return d.id.indexOf('2') >-1 });
return data.filter(function(entry){
return entry.id.indexOf('2') > -1
})
}
});
Having experienced working with large lists I would, however, suggest you to avoid using a separate filter for this and rather manipulate it in the .js code. You could easily filter the data when you query it with your $http.get like:
$scope.suggestionResult = response.data.filter(function(){
return /* condition comes here */
}
This way you are not overloading the DOM and help the browser handling AngularJS's sometimes slow digest cycle.
If you need it to be dynamic (e.g. the filtering conditions can be changed by the user) then add an ng-change or $watch or ng-click to the modifiable information and on that action re-filter $scope.suggestionResult from the original response.data
I receive from my rest api news with the specified id. When I display all news I used ng-repeat and works fine but when I want display one object this method is not working.
My .when code:
.when('/displaynews/:id',{
templateUrl: 'views/display.html',
controller: 'NewsDisplayController',
constollerAs: 'displaydash'
})
and the controller:
.controller('NewsDisplayController',
function($routeParams, NewsModel){
var displaydash = this;
var newsId = $routeParams.id;
path = 'getNewsById/'+newsId;
function getNewsById() {
NewsModel.getNewsById().then(function (result){
displaydash.news = result.data;
console.log(displaydash.news);
})
}
getNewsById();
})
Result from console.log:
Object { id="56f1ba6b275c8aa5bf4895d8", title="Tytul", text="Text", more...}
How can I display this in my html template?
I try to display in html file in this way:
<p>{{news.title}}</p>
<p>{{news.text}}</p>
But it's not working
You can go for :
angular.toJson(JSONObj);
So, here you can go for:
in Controller:
displaydash.news = result.data;
$scope.news = angular.toJson(displaydash.news);
in HTML:
<p>{{news}}</p>
The issue in your question is simple, you are trying to access news object which you have not defined, try creating a scope variable for it, you will be easily able to access it:
$scope.displaydash.news = result.data;
<p>{{displaydash.news.title}}</p>
<p>{{displaydash.news.text}}</p>
Refer: https://docs.angularjs.org/api/ng/function/angular.toJson
If result.data is an object, enclose it with square brackets and set as news, otherwise use it directly.
displaydash.news = typeof(result.data) == "object"?[result.data]: result.data;
So Im having a hard time trying to get my head wrapped around promises in angularJs. I have mixed around my code to try to do some brute force/reverse engineering understanding of it but nothing is coming out to any viable conclusion.
My Code:
Is is making a call back to get a list of repositories that I manage. These are just stored in the database as basic objects with an id and url.
Here is my view. It allows to me delete, view, and clear metadata in my database about these repos.
<div class="container" ng-controller="adminCtrl as vm">
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
<label class="control-label" >Repos:</label>
<div ng-repeat="repo in vm.repos">
<div class="clearfix">{{repo.URL}}<br>
<button class="btn btn-primary" ng-click='vm.listFiles(repo.URL)'>View Files</button>
<button class="btn btn-primary" ng-click='vm.clearFiles(repo.URL)'>Clear Files</button>
<button class="btn btn-primary" ng-click='vm.clearRepo(repo.URL)'>Delete Repo</button>
</div>
<br>
</div>
<label class="control-label" >Files:</label>
<div ng-repeat="file in vm.files">
<li>{{file.FullPath}}</li>
</div>
</div>
</div>
<!-- /.row -->
</div>
Here is my controller with some basic functions
(function (angular) {
'use strict';
var ngModule = angular.module('myApp.adminCtrl', []);
ngModule.controller('adminCtrl', function ($scope, $resource) {
//"Global Variables"
var File = $resource("/api/file/:repoUrl");
var Repo_del = $resource("/api/repo/:repoUrl");
var Repo = $resource("/api/repo");
var vm = this;
vm.files = [];
vm.repos = [];
vm.clearFiles = clearFiles;
vm.listFiles = listFiles;
vm.clearRepo = clearRepo;
init();
//Anything that needs to be instantiated on page load goes in the init
function init() {
listRepos();
}
function listRepos() {
vm.repos = Repo.query();
}
//Lists all files
function listFiles(url) {
vm.files = File.query({repoUrl: url});
}
function clearRepo(url) {
Repo_del.remove({repoUrl: url});
}
function clearFiles(url) {
File.remove({repoUrl: url});
}
});
}(window.angular));
Now this works fine and dandy. It brings back the repos and list them. I can delete, view, and remove with all the functions.
My issue came up with when I was trying to make a list item disappear on delete (instead of needing a page load). To do this I needed to find the index of the item being deleted in the array and remove it. I was gonna use some lodash to do this.Seemed simple enough. My problem is, my vm.repos array is not available within the controller.
For example. When I try to print out vm.repos with a console log within the listRepos function like so
function listRepos() {
vm.repos = Repo.query();
console.log(vm.repos);
}
I get nothing back from console.log. So this is telling me its not being assigned. Which to me is peculiar because the list is showing up in the ng-repeat on the view using vm.repos.
I have also ran into a problem when I am able to print out the array. It has TONS of promise information in it. For example if I put the console.log in the init() function I will get an array back that is jammed packed with information under a Resource object.
Im not sure how to go about and parse this down to be a manageable object. Looking at basic guides I have found some examples but nothing I can translate into my situation.
How do I properly handle api/resource promises?
Another problem im having is being able to mock out all of the api responses in my tests. This is my next feat. I do not care if it gets addressed here but I feel its stemming from the same problem.
Here is my only test I was able to write for this controller.
'use strict';
describe('adminCtrl', function () {
beforeEach(function () {
module('myApp.adminCtrl');
module('myApp');
});
describe('listRepos()', function () {
it('should return a json object representing a repository',
inject(function (_$httpBackend_, $rootScope, $controller) {
var scope = $rootScope.$new();
var mockBackend = _$httpBackend_;
var expectedResponse = {id: 12345, url: "https://github.com/myuser/myrepo.git"};
mockBackend.expectGET('/api/repo').respond([expectedResponse]);
var ctrl = $controller('adminCtrl', {$scope: scope});
mockBackend.flush();
expect(ctrl.repos.length).toEqual(1);
console.log(ctrl.repos[0]);
expect((angular.equals(ctrl.repos[0], expectedResponse)));
}));
});
});
Sorry if this is alot. Hopefully this isnt a repeated question.
EDIT to show what im trying now.
function clearRepo(url) {
$http.delete('/api/repo/', {params: {repoUrl: url}}).then(function (){
//DO THINGS
});
Express:
app.delete('/api/repo/:repoUrl', repoCtrl.clear);
repoCtrl.clear
module.exports.clear = function (req, res) {
var repoURL = req.params.repoUrl;
//console.log(repoURL);
Repo.remove({URL: repoURL}, function(err, results) {
if (err) {
console.log("ERR: " + err);
} else {
console.log('\n' + repoURL + ' repo deleted... \n');
}
});
Error im getting:
DELETE http://localhost:3000/api/repo/?repoUrl=https:%2F%2Fgithub.com%2Fuw34%2Fmyrepo.git 404 (Not Found)
First, the promise:
Used by $http
Allow chaining async request
Works like this :
var promise = $http.get('/api/values');
promise.then(function(response) {
$scope.displayData = response.data;
});
It is the new way to avoid simple callback (why avoid callback ?? check this CallbackHell :))
Nevertheless, callback can be complicated, hard to follow for debug and everyone prefer write sync code.
To simplify, Angular allow you to code something which look like sync code (but internally, it is async). To do it, $resource encapsulate a promise.
// this code return an empty array, then after received server respond, it will populate the empty array with data.
var values = VALUES.query();
// A simple version of it can be code like this
function simpleQuery() {
var arrayReference = [];
$http.get('api/values').then(function(response) {
// populate array reference with data received from server
angular.forEach(response.data, function(value) {
arrayReference.push(value);
});
// after the return, angular run a $digest
// which will display all newly received data thank to biding on your view
});
return arrayReference ;
}
By doing this, I return an empty array which will be populate on server response.
It is possible to get the promise from a $resource if you prefer :
var promise = Repo.query().$promise;
promise.then(function(response) {
$scope.displayData = response.data;
});
In 2020, you will probably use Async/Await instead $resource ;)
If you want more information, don't hesitate.
I have a rather simple question. I have a simple controller and its $scope.coords = []; renders JSON in HTML:
[24.43359375, 54.6611237221]
[25.2905273438, 54.6738309659]
[25.3344726562, 54.6102549816]
[25.2685546875, 54.6801830971]
[25.2960205078, 54.6611237221]
How can I render that JSON not in html, but in my controller itself ? The code looks like that. Please see the comment in code:
propertyModule.controller('propertyController', ['$scope', 'Property', function ($scope, Property) {
// Query returns an array of objects, MyModel.objects.all() by default
$scope.properties = Property.query();
// Getting a single object
$scope.property = Property.get({pk: 1});
$scope.coords = [];
$scope.properties = Property.query({}, function(data){
console.log(data);
angular.forEach(data , function(value){
$scope.coords.push(value.coordinates);
});
});
$scope.positions = //$Resource('realestate.property').items();
[
[54.6833, 25.2833], [54.67833, 25.3033] // those coordinates are hardcoded now, I want them to be rendered here by $scope.coords
];
}]);
First off, you're showing us a bunch of arrays, not a JSON document. But since your code seems to be working, I'll assume you do have a valid JSON to work with.
You need to consider the fact that you are making an asynchronous request here :
$scope.properties = Property.query({}, function(data) {
console.log(data);
angular.forEach(data , function(value){
$scope.coords.push(value.coordinates);
});
});
This means you won't be able to fetch data from $scope.coords before anything has arrived.
There are several ways to solve that :
You could simply fetch data while you're still in the loop :
angular.forEach(data , function(value) {
$scope.coords.push(value.coordinates);
if('your condition') {
$scope.positions.push(value.coordinates);
}
});
You could use a promise, see the angular doc.
Or you could watch over $scope.coords with $scope.$watch.
I am badly stuck with this problem of passing data from one controller to other in angularJS. Before my code was: whenever I click on templateController's div, it would trigger setTemplate with the help of ng-click... Now my objective was to send templateController's selected data to ReplyController...
After reading forum posts here, i decided to create a service called 'selectionService', so that i can transmit data between 2 controllers...
//Defined Service
proApp.service('selectionService', function() {
var selected_template;
addTemplate = function(newObj) {
selected_template = newObj;
};
getTemplate = function(){
return selected_template;
};
});
//Controller 1... where templates are selected
proApp.controller('TemplateController',function($scope, selectionService)
{
$scope.templates = [
{template_name:"Template 1", template_text:"We apologize for the interruption."} ,
{template_name:"Template 2", template_text:"Thank you for contacting us."} ,
} ,
];
// on ng-click
$scope.setTemplate = function(tmp)
{
selectionService.addTemplate(tmp);
}
});
// Controller 2 ... supposed to catch the selected template.
proApp.controller('ReplyController', function($scope, selectionService)
{
$scope.template = selectionService.getTemplate();
});
So whenever i run this code, i started getting this error
Object [object Object] has no method addTemplate...
Again I tweeked the code where they were suggesting to use Squarebrackets and put $scope , servicename and then write function with same parameters.. I don't understand why I should do this? Event after doing some changes like
[ '$scope' , 'service' , function($scope, service){}] ,
I am still not able to figure out the solution to pass data from one controller to other using service.
Could you help? What am I missing? I am very new to angularJS way of doing stuff.
I think it's actually quite simple. You just need to add your methods to the service by using this.. Currently they are declared on window. Change your service declaration to use this...
proApp.service('selectionService', function() {
var selected_template;
this.addTemplate = function(newObj) {
selected_template = newObj;
};
this.getTemplate = function(){
return selected_template;
};
});
As for using the array notation for dependencies, it's a good practice but it's not required. It'll save you from headaches if you ever run your code through a minifier.