How to switch between array data with the angular translate plugin - angularjs

I am working on an Ionic project with the plugin angular translate from Pascal Precht. I am able to translate stuff like the title in the view etc. But I need to translate my content and this is where I am a bit lost.
So I have 2 arrays (one in English and the other in Dutch), the array looks like this (each array has 14 object in them - for the purpose of this explanation i will just show 1 object in the array):
gin_mixes: [
{
id: '1',
title: 'Bathtub Gin Mix',
src: 'img/placeholder-bathtub-gin-colored.png',
backdrop: 'img/backdrop_bathtub-gin.jpg',
lang: 'en',
ingredients: [
{
ingred1: 'Bathtub Gin - 5 cl',
ingred2: 'Cardamom - 2 pcs',
ingred3: 'Clove - 3 pcs',
ingred4: 'Orange wedges - 2 pcs'
}
],
picturesIngred : [
{
pictIng1: 'img/bathtub-gin.jpg',
pictIng2: 'img/kardemon.jpg',
pictIng3: 'img/kruidnagels.jpg',
pictIng4: 'img/orange-wedges.jpg',
}
],
tonics: [
{
tonic1: 'Fever Tree Premium Indian Tonic',
tonic2: 'Indi Tonic',
tonic3: 'Schweppes Premium Tonic Water',
tonic4: 'Thomas Henry Tonic Water'
}
],
pictureTonics: [
{
pictTonic1: 'img/fever-tree.jpg',
pictTonic2: 'img/indie-tonic.jpg',
pictTonic3: 'img/schweppes-premium.jpg',
pictTonic4: 'img/thomas-henry.jpg',
}
],
utensils: [
{
utens1: 'Measuring cup',
utens2: 'Spoon',
utens3: 'Peeler',
utens4: 'Pestle'
}
],
recipe: [
{
step1: 'Fill a glass with ice cubes',
step2: 'Add the orange wedges together with the 3 pieces of clove in the glass together with 2 mashed cardamons ',
step3: 'Poor 5 cl of Bathtub Gin into the glass',
step4: 'And lastly add 20 cl of tonic to the mix'
}
]
}
]
In my settings view I give the user the option to switch between English and Dutch. When the user chooses for example Dutch then my app changes languages and I can see my translated changes (title in view etc).
But what I now need is to know is how to dynamically change the content with my 2 arrays. So if the user choose English as the language then the content has to show up in english (content from array).
I am NOT working with an external json file. The array I implemented in my service like so:
.service('GinTonicService', function($q){
return {
gin_mixes_en: [
{
id: '1',
...
},
{
id: '2',
....
},
],
gin_mixes_nl: [
{
id: '1',
...
},
{
id: '2',
....
},
],
getGinMixesEN: function(){
return this.gin_mixes_en;
},
getGinMixByIdEN: function(id){
var d = $q.defer();
this.gin_mixes_en.forEach(function(ginmix) {
if (ginmix.id === id) d.resolve(ginmix);
})
return d.promise;
},
getGinMixesNL: function(){
return this.gin_mixes_nl;
},
getGinMixByIdNL: function(id){
var d = $q.defer();
this.gin_mixes_nl.forEach(function(ginmix) {
if (ginmix.id === id) d.resolve(ginmix);
})
return d.promise;
}
}
});
Now I am able to read out the content in english like so (part of my html view):
<div class="list card padding">
<h4 class="p_benodigdheden" translate='utensils'></h4>
<br>
<div class="custom_list" ng-repeat="utensils in getGinMixById.utensils">
<ul>
<li>{{utensils.utens1}}</li>
<li>{{utensils.utens2}}</li>
<li>{{utensils.utens3}}</li>
<li ng-hide="!utensils.utens4.length">{{utensils.utens4}}</li>
</ul>
</div>
</div>
Which looks like this:

Related

Categories not listed on Interaction Studio UI

I'm implementing on a website a tool from Sales Force that is called Interaction Studio.
We need to develop into a sitemap file, where those interaction written into the file will catch the information that we need.
Here we have an example of a sitemap
Basically, the function that collects the categories is a custom function that collects the information from the breadcrumb. The function is:
const getCategoriesIdAsArray = () => {
return Evergage.resolvers.fromSelectorAttributeMultiple(
"a.c-breadcrumb__link",
"href",
(link) => {
let catId = "";
if (link.length) {
link.shift();
link.map((url, index) => {
if (index < link.length - 1) {
catId += url.split("/").reverse()[0].split("-")[0] + "|";
} else {
catId += url.split("/").reverse()[0].split("-")[0];
}
});
return [catId];
} else {
return;
}
}
);
};
To collect the information, we need to write some code in the pageTypes array. This following code is what I have in my sitemap:
pageTypes: [
{
name: "product_detail_tecnico",
action: "product_detail_tecnico",
//isMatch: () => document.body.classList.contains("is-tech-product"),
isMatch: () => {
return Evergage.DisplayUtils.pageElementLoaded(
"body#productcore.is-tech-product",
"html"
).then(() => true);
},
locale: () => {
return buildLocale();
},
catalog: {
Product: {
_id: productId,
name: Evergage.resolvers.fromJsonLd("name"),
url: Evergage.resolvers.fromJsonLd("url"),
imageUrl: Evergage.resolvers.fromJsonLd("image"),
description: Evergage.cashDom("meta[name='description']")
.first()
.attr("content")
.substring(0, 250),
decoTecnico: () => {
return bodyClasses.includes("is-deco-product");
},
inventoryCount: 1,
idc: productId && productId.split("_")[1],
idp: getProductIdFromUrl(),
price: Evergage.resolvers.fromJsonLd("offers.0.price"),
precioAnterior: Evergage.util.getFloatValue(
Evergage.cashDom(".c-product-price__before .js-old-price")
.first()
.text()
.split(" ")[0]
.replace(",", ".")
),
video: Evergage.cashDom("iframe#player").attr("src"),
categories: () => {
return getCategoriesIdAsArray();
},
},
},
]
As we can see, the last attribute, categories returns the value from the custom function that is an array with one string due to the data that I must pass in.
The data that I get on the visual editor:
In the sitemap into the pageTypes I also have this code:
{
name: "Category",
action: "Viewed Category",
isMatch: () => {
return Evergage.DisplayUtils.pageElementLoaded(
"body.categorycore",
"html"
).then(() => true);
},
catalog: {
Category: {
_id: getCategoriesId(),
//parentId: categoryParentId,
name: categoryName,
department: () => isDepartment(),
url: Evergage.resolvers.fromHref(),
description: Evergage.cashDom("meta[name='description']")
.first()
.attr("content"),
},
},
listeners: [
Evergage.listener("click", "section.c-distributive-filters", () => {
Evergage.sendEvent({
action: "Filter Results",
});
}),
],
},
This code is required because to assign a category to a product, we must have that category recorded in the UI.
As we can see in the next picture, the categories are recorded.
The event stream is recording the following:
This is the code from item:
{
description:
"Tira LED 12V DC 30LED/m 5m IP20 Ancho 10mm es una opción muy extendida si se desea disponer de una luz decorativa que consuma muy poco. Su diseño flexi...",
idc: "122262",
inventoryCount: 1,
type: "Product",
url: "https://dev61.efectoled.com/es/comprar-tiras-led-monocolor/62294-tira-led-12v-dc-smd5050-30ledm-5m-ip20.html",
idp: "62294",
price: 7.95,
imageUrl:
"https://4438d3e301b6821c9a36cfd759bc58f8/442295-thickbox_default/tira-led-12v-dc-smd5050-30ledm-5m-ip20.jpg",
name: "Tira LED 12V DC 30LED/m 5m IP20 Ancho 10mm",
decoTecnico: false,
attributes: {
idp: { value: "62294" },
decoTecnico: { value: false },
idc: { value: "122262" },
},
id: "62294_122262",
categories: [{ _id: "10|63|24", type: "c" }],
}
But when I go into the details of a product, the categories are not.
I have read all the documentation that Interaction Studio provides, but I can not understand what happens. Because in the visual editor the data is recorded and in the event stream also is recorded.
Does anybody know why this is happening? Thanks in advance

Vue.js filtering on array

I am trying to filter an array using a computed property in vue.js. I would like to search on on multiple fields, name, state, tags etc.
My data:
events: [
{
id: 1,
name: 'Name of event',
url: '#',
datetime: '2017-05-10T00:00:00Z',
description: 'The full text of the event',
state: 'VIC',
tags: [
'ordinary',
'advanced'
]
},
{
id: 2,
name: 'Another event',
url: '#',
datetime: '2017-05-12T00:00:00Z',
description: 'The full text of the event',
state: 'VIC',
tags: [
'beginner'
]
},
{
id: 3,
name: 'Great event',
url: '#',
datetime: '2017-05-18T00:00:00Z',
description: 'The full text of the event',
state: 'NSW',
tags: [
'beginner'
]
}
]
},
The following function works as expected, however I cant work out how to have it search the items in 'tags' (commented out).
searchevents: function(){
let result = this.events
if (this.filterValue){
result = result.filter(event =>
event.name.toLowerCase().includes(this.filterValue.toLowerCase()) ||
event.state.toLowerCase().includes(this.filterValue.toLowerCase())
// event.tags.toLowerCase().values().includes(this.filterValue.toLowerCase())
)
}
return result
}
The following returns a blank array, this method works ok when i have done it in angular but not in vue.
searchevents2: function(){
var searchRegex = new RegExp(this.filterValue,'i')
this.events.filter(function(event){
return !self.filterValue || searchRegex.test(event.name) || searchRegex.test(event.state)
})
}
Ideally I would either like to be able to list array items to filter by or just filter by the entire array.
Appreciate any help, first post here so be gentle. I have a lot more experience with Python than Javascript so i may also use incorrect terminology at times.
You weren't too far off.
For your searchEvents filter, you just needed to add the tag filter. Here's how you might do that.
searchevents: function(){
let result = this.events
if (!this.filterValue)
return result
const filterValue = this.filterValue.toLowerCase()
const filter = event =>
event.name.toLowerCase().includes(filterValue) ||
event.state.toLowerCase().includes(filterValue) ||
event.tags.some(tag => tag.toLowerCase().includes(filterValue))
return result.filter(filter)
}
Array.some() is a standard array method that returns true if any element of the array passes your test.
searchevents2: function(){
const searchRegex = new RegExp(this.filterValue,'i')
return this.events.filter(event =>
!this.filterValue || searchRegex.test(event.name) || searchRegex.test(event.state))
}
With searchEvents2 you really only left an errant self in there. Either you needed to set self before you executed the filter, or, as I have done here, turned it into an arrow function.
Example.
const app = new Vue ({
el: '#app',
data: {
search: '',
userList: [
{
id: 1,
name: "Prem"
},
{
id: 1,
name: "Chandu"
},
{
id: 1,
name: "Shravya"
}
]
},
computed: {
filteredAndSorted(){
// function to compare names
function compare(a, b) {
if (a.name < b.name) return -1;
if (a.name > b.name) return 1;
return 0;
}
return this.userList.filter(user => {
return user.name.toLowerCase().includes(this.search.toLowerCase())
}).sort(compare)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<div id="app">
<div class="search-wrapper">
<input type="text" v-model="search" placeholder="Search title.."/>
<label>Search Users:</label>
</div>
<ul>
<li v-for="user in filteredAndSorted">{{user.name}}</li>
</ul>
</div>

Using a pipe to filter an array of objects by an array of strings in Angular2

I am attempting to filter an array of objects which have a similar structure to this:
posts = [
{
title: 'post 1 title',
location: 'Location 1'
},
{
title: 'post 2 title',
location: 'Location 2'
},
{
title: 'post 3 title',
location: 'Location 3'
}
]
I am filtering this array of objects (above) with an array of strings (below)
locations = [
'Location 1',
'Location 2',
'Location 3'
]
How it should be working:I enter into a 'tag' style input box in the browser as many locations as I want and it should display the posts with location properties matching those location 'tags' in the locations array.
All the posts are initially displayed (which is good), then when I enter tags I am able to get the filtered objects in the log which shows that they seem to be getting filtered based on my inputs. but the html in which the posts are looped through does not show the relevant posts.
I am using firebase to store the posts, and calling my service which returns all the posts on ngOnInit()
ngOnInit() {
this._tags = [];
this._postService.getAllPosts().subscribe(posts => {
this._posts = posts;
});
}
HTML:
<!--input *edited some stuff out like the add tag function. 'term' model gets pushed into the _tags array on enter or click etc-->
<input type="text" placeholder="Search" [(ngModel)]="term [ngModelOptions]="{standalone: true}">
<!--tag list, shows tags that have been searched-->
<div class="tag" *ngFor="let t of _tags">{{t}}</div>
<!filtered post list-->
<div *ngFor="let post of _posts | tagsearchfilter:_tags">
<h4>{{post.title}}</h4>
</div>
...
Pipe filter:
import { Pipe, PipeTransform } from '#angular/core';
import { PostService } from '../../services/post/post.service';
#Pipe({
name: 'tagsearchfilter'
})
export class TagSearchFilterPipe implements PipeTransform {
transform(posts: any, tags: any): any {
let rposts = [];
if (tags === undefined || tags.length === 0 ) {
return posts;
}
posts = posts.filter(function(post){
tags.forEach(tag => {
if (
post.location.toLowerCase().includes(tag.toLowerCase())
) {
rposts.push(post);
console.log('Post location: ' + post.location + ' Tag: ' + tag);
}
});
posts = rposts;
console.log(posts);
return posts;
});
}
}

Comparing objects from two scopes to provide a value

I'll try to simplify the problem as much as I can.
Let's say I have 2 scopes
$scope.section1 = [
{label: 'label1'},
{label: 'label2'}
];
$scope.section2 = [
{value: 'one'},
{value: 'two}
];
Those scopes are used to generate buttons with ng-repeat
<button ng-repeat="item in section1 type="button">{{item.label}}</button>
and
<button ng-repeat="item in section2 type="button">{{item.value}}</button>
Now what I would like to do it to create a third scope that would attach values to the combinations of objects from the two previous ones, say:
$scope.combo = [
{ section1.label:label1 + section2.value: one = 'result1' },
{ section1.label:label2 + section2.value: one = 'result2' },
{ section1.label:label1 + section2.value: two = 'result3' },
{ section1.label:label2 + section2.value: two = 'result4' }
];
Now here comes the tricky part. What I would need to do, is to add a function that would take the values of clicked ng-repeat buttons from each section and then display the results based on the third scope in an input field or something.
So, if you click the button with label:label1 and the one with value:two the input field would show result3.
I'm very green when it comes to Angular and I have no idea how to approach it, especially that all values are strings.
If I understand correctly you could setup your combo something like ...
$scope.combo = {
"label1": {
"one": "result1",
"two": "result2"
},
"label2": {
"one": "result3",
"two": "result4"
}
}
You can then reference the correct value as combo[valueFromButton1][valueFromButton2] where valueFromButton1 and valueFromButton2 point at a model that contains the result of the clicked buttons. Your controller function then just needs to tie everything together by updating the model when the buttons are clicked.
See this plunkr ... https://embed.plnkr.co/GgorcM/
Without changing much you can also try like below provided code snippet.Run it to check the demo.
var app = angular.module('app', []);
app.controller('Ctrl',['$scope' ,function($scope) {
var key1, key2;
$scope.click = function(type, item) {
if (type == 'label') {
key1 = item;
} else if (type == 'val') {
key2 = item;
}
$scope.key = key1 + '+' + key2;
angular.forEach($scope.combo, function(val, key) {
if(val[$scope.key]){
$scope.finalVal = val[$scope.key];
}
});
};
$scope.section1 = [{
label: 'label1'
}, {
label: 'label2'
}];
$scope.section2 = [{
value: 'one'
}, {
value: 'two'
}];
$scope.combo = [{
'label1+one': 'result1'
}, {
'label2+one': 'result2'
}, {
'label1+two': 'result3'
}, {
'label2+two': 'result4'
}];
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='app' ng-controller='Ctrl'>
<button ng-repeat="item in section1" ng-click="click('label',item.label)" type="button">{{item.label}}</button>
<button ng-repeat="item in section2" ng-click="click('val',item.value)"type="button">{{item.value}}</button>
<input type="text" ng-model="finalVal"/>{{key}} {{finalVal}}
</div>

How to select objects that have a certain atribute in a json file in an Angular JS project?

I have a link to an API which lists movies, each movie has title,id etc...
API: http://private-5d90c-kevinhiller.apiary-mock.com/angular_challenge/horror_movies
It also has an offers array inside which contains a 'provider_id' property.
I need to show how many movies are available at which provider.
But I dont know how, the best I came up with was:
{{movie.offers[0].provider_id}}
But that only shows the first provider on each movie.
What I want is to extract how many movies each provider has.
My Html:
<div ng-controller="ProviderController as provider">
<div ng-repeat="movie in provider.movies">
{{movie.offers[0].provider_id}}
</div>
</div>
My Main.js:
app.controller('ProviderController', function($http) {
var provider = this;
provider.movies = [];
$http({
url: 'some/path/horror_movies',
method: "GET",
}).success(function(data) {
provider.movies = data;
});
});
Also this is the structire of the json file:
[{
"id": 140524,
"title": "Dracula Untold",
"offers": [{
"provider_id": 2,
"retail_price": 14.99,
//...
}, {
"provider_id": 2,
"retail_price": 14.99,
}, {
"provider_id": 7,
"retail_price": 14.99,
}, ]
},
{
"id": 138993,
"title": "The Purge: Anarchy",
"offers": [
// ...
]
},
]
Any ideas ? Thanks.
You will need to change the structure of your database to have providers at the top level. A function achieving something like this should iterate over every movies offers, something like this:
function getProviders (movies) {
var providers = [],
movie = {},
offer = {};
for (var i = 0, max = movies.length; i < max; i += 1) {
movie = movies[i];
for (var j = 0; j < movies[i].offers.length; j += 1) {
offer = movie.offers[j];
if (typeof providers[offer.provider_id] === 'undefined') {
providers[offer.provider_id] = { movies: [] };
}
providers[offer.provider_id].movies.push(movie);
}
}
return providers;
}
I started a fiddle here: http://jsfiddle.net/d29tu8fg/1/
Before adding a movie to a provider, you might also want to check, if that movie already exists. You only need to do that though, if – like in your data – a movie can have two different offers from the same provider.
Add the providers to the $scope and in your view show the length:
<div ng-repeat="provider in providers track by $index">
{{provider.movies.length}}
</div>

Resources