Global function to convert minutes to hours in vue-cli - vuejs2

I want to convert time (in minutes) to hours.
I have a method for that in javascript:
String.prototype.toHHMMSS = function() {
// eslint-disable-next-line no-debugger
return `0${(this / 60) ^ 0}`.slice(-2) + ":" + ("0" + (this % 60)).slice(-2);
};
While I am using this method outside the vue instances, this method works well like in the example shown below.
String.prototype.toHHMMSS = function() {
// eslint-disable-next-line no-debugger
return `0${(this / 60) ^ 0}`.slice(-2) + ":" + ("0" + (this % 60)).slice(-2);
};
var vm = new Vue({
el: '#app',
methods: {
html() {
return `<span> <strong><i>${this.time.toHHMMSS()}</i></strong> Spent in Week 2</span>`
}
},
data() {
return {
time: "121",
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-html="html()" />
</div>
But I am using the vue-cli, and want to use that method in the data. similar to the shown in the example.
But it's not working, while I used that before export default {} in the component or, I used as:
export default {
install(Vue, options) {
Vue.prototype.toHHMMSS = function (object) {
return false // dummy function for now to check if method works
}
}
}
I know of using the mixins for a similar purpose, but is there a way to make this work without the mixin?

Puts the following code in a file named helper.js or whatever you want
export function toHHMMSS(time) {
return `0${(this / 60) ^ 0}`.slice(-2) + ":" + ("0" + (this % 60)).slice(-2);
};
Then in your vue file, use import below the tag of <script>
import * as Helper from "helper.js" // Note the file location
Now you can use the following code in your function
var formatedTime = Helper.toHHMMSS(this.time)

Related

Vue 3 - Referencing composable function in loop - value returned in quotation marks and warning Maximum recursive updates exceeded in component

I'm attempting to call a composable function to convert & format a proto time object into a time string in my Vue 3 project. This function is called as many times as there are items in the array.
When I import the composable function and reference it in the template code, I get the error "Maximum recursive updates exceeded in component", as well as my result returned wrapped in quotation marks.
If I write this function manually in the component as a method, I get no such error, and the values are returned unwrapped.
My question is, why does this happen? I'm not the most well versed with composables yet, so I assume that there is some error in the way that I create and reference my composable. And why is the value returned in quotation marks? The only information I could find this is here but it did not solve my question sadly.
My composable :
import { ref, readonly } from "vue";
import moment from "moment";
import "moment-timezone";
/*
* convertTime inputs
* - proto timestamp (seconds and milliseconds)
* - format for moment object
*/
export function useAdjustTime() {
const timeZone = ref("Europe/Berlin");
const adjustedTime = ref("");
function convertTime(t, format = "MMM DD, YYYY hh:mm A z") {
let momentTime = moment.utc(t.seconds * 1000 + t.nanos / 1000000);
adjustedTime.value = momentTime.tz(timeZone.value).format(format);
return adjustedTime;
}
return { timeZone, adjustedTime: readonly(adjustedTime), convertTime };
}
And my vue file where this is referenced:
<template>
<div class="mb-5">
<div v-for="(job, i) in jobs" :key="i + 'testjob'">
{{ convertProtoToDate(job.firstVial, "ll") }} <- THIS WORKS just fine
{{ convertTime(job.firstVial, "ll") }} <- THIS line produces the errors above
</div>
</div>
</template>
<script>
import { useAdjustTime } from "#/composables/useAdjustTime";
import moment from "moment";
export default {
setup() {
const { convertTime } = useAdjustTime();
return {
convertTime,
};
},
props: {
jobs: Array,
},
methods: {
convertProtoToDate(date, format) {
return moment
.utc(date.seconds * 1000 + date.nanos / 1000000)
.format(format);
},
},
};
</script>

How to import a function from external JS file in Vue js?

I want to use an external JS function into a vue file.
Js file contains the method:
let calculateDiscount = {
PriceAfterDiscount(price, discountPercentage) {
const discountAmount = (discountPercentage * price) / 100;
return price - discountAmount;
}
};
export default calculateDiscount;
Vue file
<template>
<div v-for="product in product_data" :key="product.id">
<h4> ${{ Discount(product.price, product.sale) }}</h4>
</div>
</template>
<script>
import CalculateDiscount from "#/utilities/CalculateDiscount"; //js file containing the method
name: "ShowProduct",
methods: {
Discount(){
CalculateDiscount.PriceAfterDiscount();
}
}
</script>
I far I guess I can't import the function in method property in the right manner. Can anyone help me? Thanks in advance.
You need to update calculateDiscount object like:
let calculateDiscount = {
PriceAfterDiscount: (price, discountPercentage) => {
const discountAmount = (discountPercentage * price) / 100;
return price - discountAmount;
}
};
and then CalculateDiscount.PriceAfterDiscount(); should work fine.
In the template, you had called Discount function with two params like:
{{Discount(product.price,product.sale)}}
but in actual code you had passed nothing:
methods: {
Discount() {
calculateDiscount.PriceAfterDiscount();
}
}
Also, you have passed nothing to calculateDiscount.PriceAfterDiscount(). You need the pass the values from template to this and also return the result, otherwise it will never print nothing in UI:
methods: {
Discount(price, sale) {
return calculateDiscount.PriceAfterDiscount(price, sale);
}
}
JavaScript modules work as namespaces and don't need additional object literal or class to be wrapped around exports.
PriceAfterDiscount doesn't rely on calculateDiscount members and doesn't need to be defined as a part of it.
It can be:
export function PriceAfterDiscount(price, discountPercentage) {
const discountAmount = (discountPercentage * price) / 100;
return price - discountAmount;
}
};
And imported like:
import { PriceAfterDiscount } from "#/utilities/CalculateDiscount";
PriceAfterDiscount(...);
Or if it needs a namespace:
import * as calculateDiscount from "#/utilities/CalculateDiscount";
calculateDiscount.PriceAfterDiscount(...);

How to copy a codepen.io example into a .vue

I found a codepen.io example (https://codepen.io/srees/pen/pgVLbm) I want to play around with in the context of a .vue app I'm working on, and I need some help transferring the <script> section over.
I copied the HTML chunk into a <template> and the CSS into a <style>. I've confirmed the .vue file works within the broader context (content loads when the <script> is commented out. I also placed <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js" /> immediately before my <script> to resolve the $ not defined error I was getting. Is there something I need to import into App.vue or into this particular .vue file? When I leave <script> uncommented, I simply get a blank page loaded.
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js" />
<script>
var hidWidth;
var scrollBarWidths = 40;
...
you could define a method like this:
methods: {
renderStuff: function () {
var hidWidth;
var scrollBarWidths = 40;
var widthOfList = function(){
var itemsWidth = 0;
$('.list li').each(function(){
var itemWidth = $(this).outerWidth();
itemsWidth+=itemWidth;
});
return itemsWidth;
};
var widthOfHidden = function(){
return (($('.wrapper').outerWidth())-widthOfList()-getLeftPosi())-
scrollBarWidths;
};
var getLeftPosi = function(){
return $('.list').position().left;
};
var reAdjust = function(){
if (($('.wrapper').outerWidth()) < widthOfList()) {
$('.scroller-right').show();
}
else {
$('.scroller-right').hide();
}
if (getLeftPosi()<0) {
$('.scroller-left').show();
}
else {
$('.item').animate({left:"-="+getLeftPosi()+"px"},'slow');
$('.scroller-left').hide();
}
}
reAdjust();
$(window).on('resize',function(e){
reAdjust();
});
$('.scroller-right').click(function() {
$('.scroller-left').fadeIn('slow');
$('.scroller-right').fadeOut('slow');
$('.list').animate({left:"+="+widthOfHidden()+"px"},'slow',function(){
});
});
$('.scroller-left').click(function() {
$('.scroller-right').fadeIn('slow');
$('.scroller-left').fadeOut('slow');
$('.list').animate({left:"-="+getLeftPosi()+"px"},'slow',function(){
});
});
}
}
and run the method on mount like this:
mounted() {
this.renderStuff();
}
Side note, var is not ideal in this day and age. Recommend converting these to let.

How do I properly display data from this Vue method?

I'm new to Vue and JS.
Could someone help me understand how can I:
display the data I get from the method shown below
and format the method itself and make it look like a proper Vue method in ES6
Code:
Right now it looks like this and just displays data to console.
[...]
<script>
var d = require('../util/diskinfo')
export default {
data () {
return {
}
},
methods: {
getDrivesList () {
d.getDrives(function(err, aDrives) {
for (var i = 0; i < aDrives.length; i++) {
console.log('Drive ' + aDrives[i].filesystem)
console.log('blocks ' + aDrives[i].blocks)
console.log('used ' + aDrives[i].used)
console.log('available ' + aDrives[i].available)
console.log('capacity ' + aDrives[i].capacity)
console.log('mounted ' + aDrives[i].mounted)
}
})
}
}
}
</script>
I want to display it on the page using a loop. Something like this:
<div v-for="i in aDrives" :key="i.id">
<p>Disk name: {{aDrives[i].mounted}}</p>
<p>Disk size: {{aDrives[i].blocks}}</p>
</div>
There's going to be 2 loops - one in the method and one in the template, which makes it confusing. Should I maybe save it to data () first? I'm not sure how to do it properly.
If I understand well, you will receive an array of data and you want to display it. In this case you don't need to loop in the model and in the template. You will just save array locally and then loop through it once in the template.
I will illustrate some ES6 syntax as well in my example:
<template>
<div v-for="driver in drivers">
<p> {{ driver.mounted }} </p>
... display all the data here
</div>
</template>
<script>
import d from '../util/diskinfo'
export default {
data () {
return {
drivers: []
}
},
methods: {
getDrivesList () {
d.getDrives((err, aDrives) => (this.drivers = aDrivers))
}
}
}
</script>

How do we do e2e testing with polymer and selenium?

Angular has protractor to listen to lifecycle events in Angular.
eg: ptor.waitForAngular();
Is their a way to get selenium tests to wait for the various life-cycle events in polymer?
Currently we can have simple e2e tests running mocha, to do this is embed the tests directly in the html like how they do it in the source code.
You can just run your tests like they do here.
<script>
document.addEventListener('polymer-ready', function() {
mocha.run();
});
</script>
Eg to check for correct updates in a change watcher you can do this:
Polymer('x-test', {
bar: '',
ready: function() {
this.bar = 'bar';
setTimeout(function() {
this.zonk = 'zonk';
}.bind(this));
},
barChanged: function() {
chai.assert.equal(this.bar, 'bar', 'change in ready calls *Changed');
checkDone();
},
zonkChanged: function() {
chai.assert.equal(this.zonk, 'zonk', 'change calls *Changed without prototype value')
checkDone();
}
});
and for eg if you wanted to check a computer property is correct after the ready event you can do this:
<x-foo foo="mee" bar="too" count=3></x-foo>
<polymer-element name="x-foo" attributes="foo bar count">
<template>{{ fooBar }}:{{ fooBarCounted }}</template>
<script>
Polymer('x-foo', {
computed: {
fooBarCounted: 'repeat(fooBar, count)',
fooBar: "foo + '-' + bar"
},
repeat: function(str, count) {
var retval = '';
for (var i = 0; i < count; i++) {
retval += (i ? ' ' : '') + str + '(' + i + ')';
}
return retval;
},
ready: function() {
chai.assert.equal(this.shadowRoot.innerHTML, 'mee-too:mee-too(0) mee-too(1) mee-too(2)');
done();
}
})
</script>
</polymer-element>
Actually selenium (and other libs based on on it) can wait elements to appear on the page.
E.g. browser.waitForExist('#selector')
See API documentation here http://webdriver.io/api/utility/waitForExist.html
Hope it might be useful for you.