I18n translations not rendering in Datatable initializations? - datatables

I am trying to apply translations to a jquery dataTable. ie.
myTable.DataTable({
language: {
paginate: {
next: (I18n.t('filters.paginate.next')),
previous: (I18n.t('filters.paginate.previous'))
}
}
});
When I run:
I18n.locale //=>en (even when the locale is changed)
Below, you see the I18n json shows two different locales for the same value, only is picking up one in brackets, even though they are the same attribute ?

After some time I have found the reason for the issue was that the function I was using to initialize my dataTables was IIFE (function() { })();, and was being processed before $(document).ready, and the correct I18n locale would not update for my translations in time. So I used a regex on the URL query string with a function called in the IIFE, and set the I18n.locale to the found value:
function QueryString(item){
var svalue = location.search.match(new RegExp("[\?\&]" + item + "=([^\&]*)
(\&?)","i"));
return svalue ? svalue[1] : svalue;
}
(function() {
I18n.locale = QueryString('locale');
//initialized tables and added translations
.... })();

Related

What is the mechanism of calling a function from a template in Vue js

I am trying to learn Vue.js. I am following a tutorial on this site https://scrimba.com/p/pZ45Hz/c7anmTk. From here I am not getting something clear.
Here is the code below and my confusion as well :
<div id="app">
<wizard :name="harry" :cast="oculus_reparo" ></wizard>
<wizard :name="ron" :cast="wingardium_leviosa"></wizard>
<wizard :name="hermione" :cast="alohomora" ></wizard>
</div>
// emojify returns the corresponding emoji image
function emojify(name) {
var out = `<img src="emojis/` + name + `.png">`
return out
}
// cast returns a spell (function) that decorates the wizard
function cast(emoji) {
var magic = emojify("magic")
return function (wizard) {
return wizard + " " + magic + " " + emoji + " " + magic
}
}
Vue.component("wizard", {
props: ["name", "cast"],
template: `<p v-html="cast(name)"></p>`
})
var app = new Vue({
el: "#app",
data: {
harry : emojify("harry" ),
ron : emojify("ron" ),
hermione : emojify("hermione")
},
methods: {
// oculus_reparo returns a spell (function) that repairs glasses
oculus_reparo: cast(emojify("oculus-reparo")),
// wingardium_leviosa returns a spell (function) that levitates an object
wingardium_leviosa: cast(emojify("wingardium-leviosa")),
// alohomora returns a spell (function) that unlocks a door
alohomora: cast(emojify("alohomora"))
}
})
So far what I have got is that, I have created a component named wizard which takes two properties - name and cast. name is getting the value from data, and so far I understand that cast is calling the method with a parameter.
So both of them should return their specific image. My first confusion: Where does wizard come from and how is it showing the data.name image? If it is because of the method call in the template then why does emoji return another image?
I think the example is unnecessarily complex for the ideas you're looking to learn.
wizard is being globally registered with Vue by Vue.component("wizard", ...). When Vue interprets each wizard call in the template it will replace it with <p v-html="cast(name)"></p> which is set in the wizard component definition. Here name gets mapped to the property that is set via :name=. v-html is just saying to render as html the return value of cast(name), here cast is the function property that is passed to the component and not the cast function locally defined. Everything after that happens as you would expect where emojify returns a template literal that is passed to cast, that then returns a function, which combines the emoji and other properties.

vue-router query parameter as array with keys

I need to generate a vue-router link that contains an array with string keys as a query parameter.
I want the resulting URL to look like
url?param[key]=value
I need these kinds of query parameters to match an existing backend infrastructure, so renaming/refactoring them is not an option.
I've tried to use a router-link like the one below, but the param object just get's serialized as %5Bobject%20Object%5D. Maybe there is an option to change the way this object is serialized within vue-router?
<router-link :to="{name: 'xyz', query: {param: 'value'}}">link</router-link>
Does anyone have helpful input? Thank you :)
After spending some time vue-router GitHub issues and their docs, I figured it out.
When creating your RouteConfig, import qs and set the parseQuery and stringifyQuery methods as follows:
parseQuery: (query: any): object => {
return qs.parse(query);
},
stringifyQuery(query: any): string {
let result = qs.stringify(query, {encode: false});
return result ? ('?' + result) : '';
}
It is important to include {encode: false}, otherwise the square brackets will get URL encoded.
Addition to Martin's comment,
Exact Router config should be :
// https://github.com/ljharb/qs
import qs from 'qs';
const router = new Router({
routes: [
// ...
],
// set custom query resolver
parseQuery(query) {
return qs.parse(query);
},
stringifyQuery(query) {
var result = qs.stringify(query);
return result ? ('?' + result) : '';
}
});
and query parameters inside routes will be automatically converted url string and parsed as an object when accessing $router.query .

What's the proper way to implement formatting on v-model in Vue.js 2.0

For a simple example: textbox to input currency data.
The requirement is to display user input in "$1,234,567" format and remove decimal point.
I have tried vue directive. directive's update method is not called when UI is refreshed due to other controls. so value in textbox reverts to the one without any formatting.
I also tried v-on:change event handler. But I don't know how to call a global function in event handler. It is not a good practice to create a currency convert method in every Vue object.
So what is the standard way of formatting in Vue 2.0 now?
Regards
Please check this working jsFiddle example: https://jsfiddle.net/mani04/bgzhw68m/
In this example, the formatted currency input is a component in itself, that uses v-model just like any other form element in Vue.js. You can initialize this component as follows:
<my-currency-input v-model="price"></my-currency-input>
my-currency-input is a self-contained component that formats the currency value when the input box is inactive. When user puts cursor inside, the formatting is removed so that user can modify the value comfortably.
Here is how it works:
The my-currency-input component has a computed value - displayValue, which has get and set methods defined. In the get method, if input box is not active, it returns formatted currency value.
When user types into the input box, the set method of displayValue computed property emits the value using $emit, thus notifying parent component about this change.
Reference for using v-model on custom components: https://v2.vuejs.org/v2/guide/components.html#Form-Input-Components-using-Custom-Events
Here is a working example: https://jsfiddle.net/mani04/w6oo9b6j/
It works by modifying the input string (your currency value) during the focus-out and focus-in events, as follows:
<input type="text" v-model="formattedCurrencyValue" #blur="focusOut" #focus="focusIn"/>
When you put the cursor inside the input box, it takes this.currencyValue and converts it to plain format, so that user can modify it.
After the user types the value and clicks elsewhere (focus out), this.currencyValue is recalculated after ignoring non-numeric characters, and the display text is formatted as required.
The currency formatter (reg exp) is a copy-paste from here: How can I format numbers as money in JavaScript?
If you do not want the decimal point as you mentioned in question, you can do this.currencyValue.toFixed(0) in the focusOut method.
I implemented a component. According to Mani's answer, it should use $emit.
Vue.component('currency', {
template: '<input type="text"' +
' class="form-control"' +
' :placeholder="placeholder""' +
' :title="title"' +
' v-model="formatted" />',
props: ['placeholder', 'title', 'value'],
computed: {
formatted: {
get: function () {
var value = this.value;
var formatted = currencyFilter(value, "", 0);
return formatted;
},
set: function (newValue) {
var cleanValue = newValue.replace(",", "");
var intValue = parseInt(cleanValue, 10);
this.value = 0;
this.value = intValue;
}
}
}
}
);
Using Vue custom directives + .toLocaleString() is also a very good option.
Vue.directive("currency", {
bind(el, binding, vnode) {
el.value = binding.value && Number(binding.value).toLocaleString('en-US', {style: 'currency', currency: !binding.arg ? 'USD' : binding.arg });
el.onblur = function(e) {
e.target.value = Number(e.target.value).toLocaleString('en-US', {style: 'currency', currency: !binding.arg ? 'USD' : binding.arg});
};
el.onfocus = function(e) {
e.target.value =
e.target.value && Number(e.target.value.replace(/[^\d.]/g, ""));
};
el.oninput = function(e) {
vnode.context.$data[binding.expression] = e.target.value;
};
}
});
Here is the example link: https://codepen.io/Mahmoud-Zakaria/pen/YzPvNmO

vue js returned value gives undefined error

i want to check the returned value of $http.get() but i get undefined value. Here is my vue js code:
var vm = new Vue({
el: '#permissionMgt',
data: {
permissionID: []
},
methods:{
fetchPermissionDetail: function (id) {
this.$http.get('../api/getComplaintPermission/' + id, function (data) {
this.permissionID = data.permissionID; //permissionID is a data field of the database
alert(this.permissionID); //*****this alert is giving me undefined value
});
},
}
});
Can you tell me thats the problem here?.. btw $http.get() is properly fetching all the data.
You need to check what type is the data returned from the server. If #Raj's solution didn't resolve your issue then probably permissionID is not present in the data that is returned.
Do a colsole.log(data) and check whether data is an object or an array of objects.
Cheers!
Its a common js error. Make the following changes and it will work.
fetchPermissionDetail: function (id) {
var self = this; //add this line
this.$http.get('../api/getComplaintPermission/' + id, function (data) {
self.permissionID = data.permissionID; //replace "this" with "self"
});
},
}
the reason is this points to window inside the anonymous function function()
This is a well known js problem. If you are using es2015 you can use arrow syntax (() => { /*code*/ }) syntax which sets this correctly

Dojo i18n with lang.replace doesn't work

I have two template files: one for the form (loginFormTemplate) and one for the dialog (dialogTemplate). When I put them togheter I only get the i18n on my form (like ${i18n.username}, etc.), but not my dialog html it's says ${undefined}. I have clearly defined it in my nls file. Why? Here's my code when I construct my dialog.
var template = lang.replace(dialogTemplate, {
form: loginFormTemplate
});
var contentWidget = new (declare(
[_Widget, _TemplatedMixin, _WidgetsInTemplateMixin],
{
templateString: template,
i18n: i18n
}
));
I could create "variables" just like my form within the dialoTemplate and pass my i18n value, but I don't find it quite elegant. I just want to do it once. So, instead it would be like this.
var template = lang.replace(dialogTemplate, {
form: loginFormTemplate,
_ok: i18n.okLabel,
_cancel: i18n.cancelLabel
});
var contentWidget = new (declare(
[_Widget, _TemplatedMixin, _WidgetsInTemplateMixin],
{
templateString: template,
i18n: i18n
}
));
Here's my solution with with phusick answer (my form is notated %[]):
var template = lang.replace(
dialogTemplate,
{form: loginFormTemplate},
/\%\[([^\]]+)\]/g
);
I'm not by my computer, but I guess calling 'lang.replace' replaces not only {form}, but also your ${i18n.*} with undefined since only 'form' is defined when calling 'lang.replace'.
Edit: You can use 'lang.replace' with a custom pattern to avoid conflicts between i18n and string concatenation: http://livedocs.dojotoolkit.org/dojo/_base/lang#advanced-usage