Vuejs pass arguments from body to function like pure JS - vue.js

I'm trying to pass in an argument to a function that I enter into my view in order to run code on said function.
Currently I have a 5 functions that all basically do the same thing, and I'm trying to refactor them into 1 that takes the values I pass and performs some logic. It might be easier to explain what I'm trying to do with code.
This is my current code in my view:
<v-card-text :class="darkBodyPurpleCardClassFix">Manage</v-card-text>
<v-card-text :class="lightBodyPurpleCardClassFix">Fees</v-card-text>
And then here are those two functions bound to class both under computed:
lightBodyPurpleCardClassFix(){
switch (this.$vuetify.breakpoint.name) {
case 'xs': return '450px';
case 'sm': return this.mediumLightPurpleBodyCLassList;
case 'md': return this.mediumLightPurpleBodyCLassList;
case 'lg': return this.largeLightPurpleBodyCLassList;
case 'xl': return this.largeLightPurpleBodyCLassList;
}
},
darkBodyPurpleCardClassFix(){
switch (this.$vuetify.breakpoint.name) {
case 'xs': return '450px';
case 'sm': return this.mediumDarkPurpleBodyClassList;
case 'md': return this.mediumDarkPurpleBodyClassList;
case 'lg': return this.largeDarkPurpleClassList;
case 'xl': return this.largeDarkPurpleClassList;
}
},
What I'd love to do is to just pass in some arguments, and use those arguments in the function. Something along these lines
<v-card-text :class="classFix(purple, light)">Manage</v-card-text>
And then use those in a function something like this:
classFix(color, value ){
doSomethingWithColor(color);
this.data = value;
};
That color and value are arguments that I would enter into my own code so I could adjust the class list all with 1 function instead of the handful I have now.
EDIT:
This is what some of the data elements look like:
mediumPurpleCreateClassList: ['body-2', 'pb-3', 'pt-2', 'px-2', 'my_dark_purple_section'],
largePurpleCreateClassList: ['subheading', 'pb-3', 'pt-2', 'px-2', 'my_dark_purple_section'],
And what I'd like to do is just pass into a function medium & purple & create and then run my logic off of those arguments.

You could create a method like:
methods: {
// ...
classFix(darkOrLight, color) {
switch (this.$vuetify.breakpoint.name) {
case 'xs': return '450px';
case 'sm': return this['medium' + darkOrLight + color + 'ClassList'];
case 'md': return this['medium' + darkOrLight + color + 'ClassList'];
case 'lg': return this['large' + darkOrLight + color + 'ClassList'];
case 'xl': return this['large' + darkOrLight + color + 'ClassList'];
}
}
}
And use (bind) it in the template as follows:
<v-card-text :class="classFix('dark', 'purple')">Manage</v-card-text>
<v-card-text :class="classFix('light', 'purple')">Fees< /v-card-text>
Reasoning:
This alternative takes advantage of JavaScript's property accessor syntax.
Basically, any property present like:
this.mediumLightPurpleBodyCLassList
Can be acessed through:
this['mediumLightPurpleBodyCLassList']
Notice that what is between [ and ] are strings. And being strings, you can use any variable:
var myField = 'mediumLightPurpleBodyCLassList';
this[myField];
And create/manipulate that variable in anyway you would with any regular string variable:
var myColor = 'LightPurple';
var myField = 'medium' + color + 'BodyCLassList';
this[myField];
And, in the above suggested classFix method, those variables are the functions arguments (which, in the end of the day, are local variables).

Related

How to create v-autocomplete which first shows items startsWith and then shows items indexOf

I would like to create a vuetify autocomplete with a custom filter that first shows the hits that start with the searchtext and then show the hits that not start with the searchtext, but have the searchtext somewhere in the middle.
I now have a custom filter like this, but this filter is not prioritizing words that start with the searchtext:
customFilter(item, queryText) {
const textOne = item.description.toLowerCase();
const textTwo = item.code.toLowerCase();
const searchText = queryText.toLowerCase();
return (
textOne.indexOf(searchText) > -1 || textTwo.indexOf(searchText) > -1
);
}
},
Codepen (Type 'ma' for example)
I believe you need to sort it manually, filter returns only true/false whether item is a match.
// https://stackoverflow.com/a/36114029/1981247
var _sortByTerm = function (data, term) {
return data.sort(function (a, b) {
// cast to lowercase
return a.toLowerCase().indexOf(term) < b.toLowerCase().indexOf(term) ? -1 : 1;
});
};
Then pass sorted array to items prop
<v-autocomplete :items="computedItems"
...
computed: {
computedItems() {
return _sortByTerm(this.states, this.search.toLowerCase())
},
},
Note this is just to get you started, and you might need to change code a bit according to the data (and filters) you are using, e.g. _sortByTerm works only on array of strings, but in the link there is a solution for sorting arrays of objects also.

vue.js dynamically adding to a list of components

I'm having trouble dynamically adding to a list of components.
I've defined the list in the data element "things" of the vue document. For each object in "things" there is a component loaded onto the page
data() {
return {
things: []
}
}
I use something like the code below to load each of the things on the page.
<div v-for="thing in things" :key="thing.objectId">
Then I load in more elements and add them to the list
let temp = JSON.parse(JSON.stringify(results))
vm.things = vm.things.concat(temp)
And when I run it in dev I get the following
[Vue warn]: You may have an infinite update loop in a component render
function.
Other then the error message, the code works in dev mode but crashes the browser when run in production.
I've narrowed it down to this code, there is a bit in the loop which prints out a heading which is the month the data belongs to, so it might say January, then list all the data under january, then onto the next month and so on
showDate(data) {
this.currentDataMonth = helperfunctionsgetDate_format_month_year(data)
if (this.currentDataMonth != this.currentmonth) {
this.currentmonth = this.currentDataMonth
return "<h2>" + this.currentmonth + "</h2>"
} else {
return ""
}
Your issue is caused by the fact that you both modify the state, and use the state from the same method.
showDate(data) {
this.currentDataMonth = helperfunctionsgetDate_format_month_year(data) // set of the state
if (this.currentDataMonth != this.currentmonth) { // get of the state
this.currentmonth = this.currentDataMonth
return "<h2>" + this.currentmonth + "</h2>"
} else {
return ""
}
Since you directly use those variables inside your function, make them local to the function
showDate(data) {
const currentDataMonth = helperfunctionsgetDate_format_month_year(data)
if (currentDataMonth != undefined) {
const currentmonth = currentDataMonth
return "<h2>" + currentmonth + "</h2>"
} else {
return ""
}
Since the purpose of the code is to list every month under its own heading, you should do that using a computed function to return a list of data per month, and use 2 loops to loop over that

Vue.js: error setting a computed property

in the following code (jsbin available here) I have two input elements, a range and a text, bound together via a computed property.
var vm = new Vue({
el: '#main-container',
data: {
sliderValue: 100,
},
computed: {
actualValue: {
get: function() {
if (this.sliderValue <= 100) {
return this.sliderValue;
} else {
return Math.round(this.sliderValue * 12.5 - 1150);
}
},
/* set won't work for val > 100*/
set: function(val) {
if (val <= 100) {
this.sliderValue = val;
} else {
this.sliderValue = Math.round((val + 1150)/12.5);
}
}
}
},
methods: {
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
<div id="main-container">
<input type="range" v-model="sliderValue" min=1 max=132>
<input type="text" v-model="actualValue">
<p>Slider: {{sliderValue}}</p>
<p>Actual: {{actualValue}}</p>
</div>
The range goes from 1 to 132, and its range is mapped [1..500] in the text input, with a simple transformation (basically it's a linear mapping with two different slopes for [1..100] and [101..132]) using the actualValue computed property.
Getting actualValue works as expected: dragging the slider correctly updates the input text with appropriate values in the range [1..500].
I'm not able to find a way to set actualValue, though. I'd like to be able to type a value in the text input, and make the slider's thumb update accordingly to the inverse transformation (val + 1150)/12.5.
It works as long as the typed number is in the range [1..100], but it "explodes" for numbers >100, e.g. 101 makes the sliderValue jump at 80892 and actualValue is then re-calculated as 1010000. As far as I understand, it's a looping-feedback scenario.
I've tried also alternative approaches (watch; v-on:change in the text input; using a third variable) to no avail.
Thanks in advance for any suggestion!
It's an amazing puzzle, and challenged me for a long time!
Look at the screenshot below. Your sliderValue and actualValue are strings, not integers. When you set actualValue as 101, you are actually setting it as a string value of "101"
Now, your sliderValue = ((actualValue + 1150)/12.5)
"101" + 1150 = "1011150" (another string!, try it in the developer console)
That messes up your entire calculation. Now you know how to fix it :-)
And you need to get that Vue devtools from here: https://github.com/vuejs/vue-devtools
EDIT: Response to comment #3
Here is the modified jsBin: http://jsbin.com/mahejozeye/1/edit?html,js,output
The only difference is introduction of two console.log statements in your map2 function. This helps you identify if your non-linear mapping function is working correctly or not. If you keep your developer console open, you will see what is happening in this function.
Case 1: When you set the value radius = 25 using the text box, your sliderRadius gets set to 111.55518394648828 and your radius again gets re-calculated as 25. So it comes around in a full circle and everything is stable here.
Case 2: When you set the value radius = 55, your sliderRadius gets set to 173.03607214428857 through your non-linear map2() function, which resets radius to 51.29869180420927
Clearly there is a circular dependency issue. Your sliderRadius and radius are very much dependent on each other and therefore radius is unable to take the value between 51 and 58.
You need to evaluate why it happens, as it has a lot to do with the non-linear mapping function that you have defined. The moment radius can take stable values at 55 (through the map2 function), then your current problem will be resolved.
The simplest fix is to set your input type to number:
<input type="number" v-model="actualValue">
or you can convert your value to an integer with something like:
set: function(val) {
var intVal = parseInt(val, 10);
if (!isNaN(intVal)) {
if (intVal <= 100) {
this.sliderValue = Math.max(1, intVal);
} else {
this.sliderValue = Math.min(132, Math.round((intVal + 1150) / 12.5));
}
}
}

enum values passing as arguments in Objective-C

i have an enum.
Example:
enum events
{
MOVE_UP = 0,
MOVE_DOWN,
MOVE_RIGHT,
MOVE_LEFT,
};
i want to pass particular enum value as function arguments. for example:
my method definition is
(void) invokeEvents:(enum events)events withMessage:(NSDictionary*)message;
while calling this method i am passing arguments like:
[self invokeEvents:MOVE_UP|MOVE_DOWN|MOVE_RIGHT withMessage:message;
while checking the received parameter events is value is always last value of list of MOVE_UP|MOVE_DOWN|MOVE_RIGHT values. MOVE_RIGHT 2 as per enum value.
but i want all the values like "MOVE_UP|MOVE_DOWN|MOVE_RIGHT" equal 0, 1 and 2.
how can i pass the parameter so that i can get all values.
kindly give suggestion for my problem.
Thanks in advance.
Change your enum to:
{
MOVE_NONE = 0
MOVE_UP = 1<<0,
MOVE_DOWN = 1<<1,
MOVE_RIGHT = 1<<2,
MOVE_LEFT = 1<<3,
};
So you can pass parameters exactly as you want: MOVE_UP|MOVE_DOWN|MOVE_RIGHT.
And in invokeEvents:withMessage: check
if(events & MOVE_UP)
{
}
if(events & MOVE_DOWN)
{
}
...
.

Implement the same function in AS2 for an Array

I have an array, and I would like to make a function onRelease for all of the array positions.
The code would be like:
pick = new Array(2,3,4);
var botoes1:MovieClip = lev.attachMovie("block", "block_"+lev.getNextHighestDepth(), lev.getNextHighestDepth(), {_x:550, _y:1*22});
_root.botoes1.gotoAndStop(pick[1]);
var botoes2:MovieClip = lev.attachMovie("block", "block_"+lev.getNextHighestDepth(), lev.getNextHighestDepth(), {_x:550, _y:2*22});
_root.botoes2.gotoAndStop(pick[2]);
var botoes3:MovieClip = lev.attachMovie("block", "block_"+lev.getNextHighestDepth(), lev.getNextHighestDepth(), {_x:550, _y:3*22});
_root.botoes3.gotoAndStop(pick[3]);
for(i=0;i<3;i++){
_root['botoes'+i].onRelease() = Function () {
}
}
but it doesn't work this way...
and if possible, how can I make the MovieClip declaring for all the buttons in an for loop?
Couple syntax errors there, here's what this line should look like:
_root['botoes' + i].onRelease = function()
{
// Function body.
//
}
Your previous code was trying to assign the result of _root['botoes' + i].onRelease() (which would have been undefined) to the result of Function() (which would have been a Function object).