Angular Translate default translate value while using filter - angular-translate

Is there any way to provide the translate-default value while using the filter instead of directive?
e.g:
How to achieve the same results as this
<h3 translate="TEST" translate-default="Not present"></h3>
with filter format
{{ 'TEST' | translate }}
How do i put the "translate-default" attribute when using the translate filter?
What i need to do is show the original text if the key is not present.

I have created a wrapping filter for that purpose:
.filter('txf', ['$translate', ($translate: angular.translate.ITranslateService) => {
return (input: string, stringIfNotAvailable: string = '') => {
const translation = $translate.instant(input);
return translation === input ? stringIfNotAvailable : translation;
};
}]);

Related

vuejs pass extra parameter to function

Is it possible within Quasar Form rules to pass extra parameter?
This had to do with the following template code:
<q-field outlined v-else-if="prop.component === 'checkbox'"
class="q-gutter-sm"
v-model="dataRef[key]"
:label="prop.label"
:rules="[isCheckLimit]"
>
<q-option-group
style="margin-top:20px;"
:options="prop.options"
type="checkbox"
v-model="dataRef[key]"
/>
</q-field>
The function:
const isCheckLimit = (v) => {
return v.length > 2 || t('checked-to-much')
}
I want that number 2 to be dynamic instead of static, is it possible to pass for example a number to that function? I cant find any clear information about that?
Thank you in advance.
You have to define your rule as function in your rules array, first lets update your validation function to accept second argument, I will also set it to default value of 2:
const isCheckLimit = (v, minLength = 2) => {
return v.length > minLength || t('checked-to-much');
};
Now if you use this for your rules:
:rules="[(value) => isCheckLimit(value, 4)]"
Your validation function will use 4 for minLength instead of default 2.
Original way will also work:
:rules="[isCheckLimit]"
But will use the default value of 2 for minLength

Correct way to implement drill-down tags in vue with vuetify

I am using a v-chip-group with v-chips to represent a tag cloud for records in my database. I have an object array with records that look something like { key:'device', count:100}. A record could have multiple tags, so as you click on a tag, a new query is made that filters on that tag, the result will then have a new tag cloud with a subset of the previous.
It looks something like this:
tag1 (1000), tag2 (100), tag3 (100)
When you click on tag1 you end up with:
tag1 (1000), tag3 (15) (no tag2 because there is no overlap between tag1 and tag2).
Here is the relevant template code:
<v-chip-group v-model="selectedTag" multiple #change="refresh">
<v-chip v-for="tag in tags" :key="tag.key" active-class="primary">
<v-avatar left class="grey">{{ tag.count }}</v-avatar>
{{ tag.key }}
</v-chip>
</v-chip-group>
The problem I have is that in the typescript I do something like this:
refresh() {
// get simple array of tag strings
const selectedTags = this.selectedTag.map((value: any) => {
if (this.tags && this.tags[value]) {
return this.tags[value].key
} else {
return null
}
}).filter((value: any) => {
return value != null
})
Promise.all([
...
ApiCall('GET', 'tags', {limit: 1000, tags: selectedTags}),
...
).then((values) => {
// decode response from server into new tags
this.tags = values[2].series['0'].values.map((item: any) => {
return {key: item.bucket, count: item.doc_count}
})
const newTags: number[] = []
this.tags.forEach((tag, index) => {
// find the new index of the previously selected tags and save them
if (selectedTags.find(st => {
return st === tag.key
})) {
newTags.push(index)
}
})
// update selectedTag with the new value
this.$set(this, 'selectedTag', newTags)
// did not work this.selectedTag = newTags
})
}
What I'm seeing is that when I click a chip, it correctly fires the #change event and calls refresh, but then when the refresh finishes, I see an additional refresh get called with an empty selectedTag, which clears my filters and recalls the above functionality.
Is there a way to get #change to fire when a chip is changed, but not fire (or filter it out) when the event is generated by changing the data referenced by v-model?

Am I overwriting computed property filter in Vue?

I am trying to create a reactive filter for an array in Vue. My starting array comes from an API call which returns this.features (geojson features). I am filtering on a nested array. This works -- but when I enter a search term and then backspace back out to an empty string, and enter another string, I am not filtering the original array but appear to be filtering the already-filtered array. How could I filter again on the original array from the API call?
computed property:
filteredFeatures() {
if (this.searchTerm == '') {
return this.features
}
// filter on nested array
let filtered = this.features.filter(feature => {
feature.properties.site_observations = feature.properties.site_observations.filter(
el => JSON.stringify(el).match(this.searchTerm, 'i')
)
return feature.properties.site_observations.length > 0
})
return filtered
}
I have looked at Vue filtering objects property but I cannot make that code work (it uses Object.assign()). Thanks for any ideas.
Your computed property is mutating feature.properties.site_observations, that's a nono. Computed properties should be read only.
filteredFeatures() {
if (this.searchTerm == '') {
return this.features
}
// filter on nested array
let filtered = this.features.filter(feature => {
const site_observations = feature.properties.site_observations.filter(
el => JSON.stringify(el).match(this.searchTerm, 'i')
)
return site_observations.length > 0
})
return filtered
}
It seems here is your problem:
feature.properties.site_observations = feature.properties.site_observations.filter(
el => JSON.stringify(el).match(this.searchTerm, 'i')
)
Because this code filter feature and alter the proprieties of feature.properties.site_observations. Then, in the next read the value is alter. We say that your function it is not pure, because it alter the state of feature.
So, what you should do is:
let anotherVariable = feature.properties.site_observations.filter(
el => JSON.stringify(el).match(this.searchTerm, 'i')
)
Therefore, on a function, avoid alter state of objects, this lead to bugs.
On further checking, the above answer returns all site_observations, not just the ones that match the search. A much better solution is the following, using map to avoid overwriting the data, and the object spread operator to perform an object assign, and drilling down through the nested objects as follows:
filteredFeatures() {
return this.features
.map(feature => ({
...feature,
properties: {
site_observations: feature.properties.site_observations.filter(
element => {
return JSON.stringify(element).match(new RegExp(this.search, 'i'))
}
)
}
}))
.filter(feature => feature.properties.site_observations.length)
}

Kendo-vue-ui wrapper kendo-grid-column format phone number in grid

I have been trying to use vuejs filter in kendo-grid-column
<kendo-grid-column field="phone" title="Phone" :template="`kendo.toString(phone) | phoneformat`" width="10%"></kendo-grid-column>
Rather being displayed as formatted string the result is displayed as
Filter I am using as:
const filters = [
{
name: "phoneformat",
execute: value => {
debugger
var piece1 = phoneNumber.substring(0, 3); //123
var piece2 = phoneNumber.substring(3, 6); //456
var piece3 = phoneNumber.substring(6); //7890
//should return (123)456-7890
return kendo.format("({0})-{1}-{2}", piece1, piece2, piece3);
}
}
];
export default filters;
I have been registering the filter globally as:
import filters from './shared/extension'
filters.forEach(f => {
Vue.filter(f.name, f.execute)
})
Help me what i am missing here.
:template="`kendo.toString(phone) | phoneformat`"
You have backticks around the :template attribute value, meaning you're binding the template prop to a JavaScript template literal which evaluates to the literal string
"kendo.toString(phone) | phoneformat"
The solution is to simply bind an expression instead
<kendo-grid-column :template="phone | phoneformat" ...
See
https://v2.vuejs.org/v2/guide/filters.html
https://v2.vuejs.org/v2/guide/components-props.html#Passing-Static-or-Dynamic-Props

Ember.js input fields

Is it possible to use standard HTML5 input fields in an Ember.js view, or are you forced to use the limited selection of built in fields like Ember.TextField, Ember.CheckBox, Ember.TextArea, and Ember.select? I can't seem to figure out how to bind the input values to the views without using the built in views like:
Input: {{view Ember.TextField valueBinding="objectValue" }}
Specifically, I'm in need of a numeric field. Any suggestions?
EDIT: This is now out of date you can achieve everything above with the following:
{{input value=objectValue type="number" min="2"}}
Outdated answer
You can just specify the type for a TextField
Input: {{view Ember.TextField valueBinding="objectValue" type="number"}}
If you want to access the extra attributes of a number field, you can just subclass Ember.TextField.
App.NumberField = Ember.TextField.extend({
type: 'number',
attributeBindings: ['min', 'max', 'step']
})
Input: {{view App.NumberField valueBinding="objectValue" min="1"}}
#Bradley Priest's answer above is correct, adding type=number does work. I found out however that you need to add some attributes to the Ember.TextField object if you need decimal numbers input or want to specify min/max input values. I just extended Ember.TextField to add some attributes to the field:
//Add a number field
App.NumberField = Ember.TextField.extend({
attributeBindings: ['name', 'min', 'max', 'step']
});
In the template:
{{view App.NumberField type="number" valueBinding="view.myValue" min="0.0" max="1.0" step="0.01" }}
et voile!
Here is my well typed take on it :
App.NumberField = Ember.TextField.extend({
type: 'number',
attributeBindings: ['min', 'max', 'step'],
numericValue: function (key, v) {
if (arguments.length === 1)
return parseFloat(this.get('value'));
else
this.set('value', v !== undefined ? v+'' : '');
}.property('value')
});
I use it that way:
{{view App.NumberField type="number" numericValueBinding="prop" min="0.0" max="1.0" step="0.01" }}
The other systems where propagating strings into number typed fields.
You may also wish to prevent people from typing any old letters in there:
App.NumberField = App.TextField.extend({
type: 'number',
attributeBindings: ['min', 'max', 'step'],
numbericValue : function (key,v) {
if (arguments.length === 1)
return parseFloat(this.get('value'));
else
this.set('value', v !== undefined ? v+'' : '');
}.property('value'),
didInsertElement: function() {
this.$().keypress(function(key) {
if((key.charCode!=46)&&(key.charCode!=45)&&(key.charCode < 48 || key.charCode > 57)) return false;
})
}
})
Credit where its due: I extended nraynaud's answer
This is how I would do this now (currently Ember 1.6-beta5) using components (using the ideas from #nraynaud & #nont):
App.NumberFieldComponent = Ember.TextField.extend
tagName: "input"
type: "number"
numericValue: ((key, value) ->
if arguments.length is 1
parseFloat #get "value"
else
#set "value", (if value isnt undefined then "#{value}" else "")
).property "value"
didInsertElement: ->
#$().keypress (key) ->
false if (key.charCode isnt 46) and (key.charCode isnt 45) and (key.charCode < 48 or key.charCode > 57)
Then, to include it in a template:
number-field numericValue=someProperty