How to bind function in vue js v-model? - javascript

I asked a question which might be unclear to someone. So, I deleted that question and ask again with new approach. I have an API response something like this:
{
id: 2,
name: 'Item 1',
items: [
{
slug: 'Phase 1',
values: [
{
highValue: '12',
lowValue: '8',
color: 'red'
},
{
highValue: '15',
lowValue: '5',
color: 'green'
}
]
},
{
slug: 'Phase 2',
values: [
{
highValue: '14',
lowValue: '6',
color: 'red'
},
{
highValue: '15',
lowValue: '5',
color: 'green'
}
]
}
]
},
{
id: 3,
name: 'Item 2',
items: [
{
slug: 'CBC',
values: [
{
highValue: '10',
lowValue: '7',
color: 'green'
},
{
highValue: '12',
lowValue: '3',
color: 'red'
}
]
}
]
}
I have static block for High Value, Low Value, Red & Green in my HTML. So, for those static blocks, I need to pick appropriate value from the response. For example, for High Value & Red block, I need to pick highValue from the response when color: 'red'. So, I write four function for example:
redHigh (item) {
const res = item.filter(obj => {
return obj.color === 'red'
})
return res[0].highValue
}
Now, I tried to bind the function in v-model like this way:
<v-text-field
outlined
:v-model="redHigh(sub.values)"
placeholder="High"
></v-text-field>
But, that was not working. If I wrote :value instead of :v-model, that would work. But, in that case I don't get the changed value after clicking save button.
save (formIndex) {
console.log(this.items[formIndex])
}
How to solve that?
Codepen Demo

v-model is not for a function; it's for a Vue's data property.
However, I understand your app requirement.
You just need to create Vue computed properties, that can generate a dynamic array using a custom function bind input event from your text field
you can read $emit or v-bind documentation about it
I just read the API of v-text-field component here https://vuetifyjs.com/en/api/v-text-field/#props.
Just need to update it to use value prop and bind change event
Which is would be like this
<div v-for="(sub, index) in item.items" :key="sub.slug">
<v-text-field
outlined
:value="redHigh(sub.values)"
#change="updateSubValue(index, 'red', 'high')"
placeholder="High"
></v-text-field>
updateSubValue(index, color, value) {
// find current sub by index
// find current value's key by color and value
// update vue data
}
It might index first, been a long time I don't develop the Vue app
<div v-for="(index, sub) in item.items" :key="sub.slug">
Or you can find the current sub by slug, no need to add index

Related

v-if and splice on users pick from v-model

I have the following code (from a tutorial, but I want to expand it a bit):
<div style="margin-top: 10px;">
v-for="task in taskItems"
:key="task.id"
<q-icon :name="task.icon"/>
<div
{{ task.text }}
</div>
</div>
my taskItems array looks like this:
taskItems: [
{
id: 1,
icon: 'settings',
text: 'Dolor, sit amet consectetm tot',
name: 'style'
},
{
id: 2,
icon: 'exit',
text: 'Lossssr dolor, sit amet consectetm tot',
name: 'getaway'
},
{
id: 3,
icon: 'lego',
text: 'Lomet consectetm tot',
name: 'buildingblocks'
},
{
id: 4,
icon: 'lego',
text: 'Lomet consectetm tot',
name: 'buildingblocks'
}
]
and I have the following v-model:
numberOfTasks: [
{ value: '1', label: '1' },
{ value: '2', label: '2' },
{ value: '3', label: '3' },
{ value: '4', label: '4' },
}
where a user can pick an object by clicking on a button (left out since that isn't the primary focus) and if they choose the first, then it is equal to value '1', if they choose the second, then it's equal to '2', etc.
The thing is, that I want my v-for at the top, which contains 4 tasks, to show the number of elements from its array equal to the numberOfTasks, that the user chooses.
So if the user chooses value: '3', then the v-for will only show 3 tasks from the tasks array.
I am new to Vue and have tried several things out, but none works.
How do I bind these together and do I need to use task.splice in my ?
Anyone have an idea, what to do?
I'll assume taskItems is a property of data as well as numberOfTask which store the value choosen form numberOfTasks.
You need to change v-for="task in taskItems" in v-for="task in actualTaskItems" where actualTaskItems is a computed property like so
// …
computed: {
actualTaskItems() {
return this.taskItems.splice(0, this.numberOfTask);
}
}
This is freehand so it might not be 100% correct, but you can simulate an index for loop in Vue. I've added a variable selectedNumberOfTasks which would just be a number (a data variable or something) that represents what the user has selected.
<div v-for="index in selectedNumberOfTasks" :key="index">
{{ taskItems[index].text }}
</div>
This will count up in the variable index to a max of selectedNumberOfTasks.
The JS for loop equivalent would be
for (let i = 0; i < this.selectedNumberOfTasks; i++)

selectize.js and vue.js 2 ajax loaded optons

I'm using vuejs#2.3.3, selectize#0.12.4, vue2-selectize.
I have a pretty big form with a few select inputs.
All options are loaded by ajax into a one property, which is initialized with a demo data before being replaced by ajax data:
addTrackData : {
styles : [
{ id: 1, title: 'style 1' },
{ id: 2, title: 'style 3' },
{ id: 3, title: 'style 2' },
],
authors: [
{inn: '111', name: 'demo 1'},
{inn: '222', name: 'demo 2'},
{inn: '333', name: 'demo 3'}
]
....
},
And I've got 2 problems:
1) If I use settings in this way, options doesn't loads at all:
<selectize v-model="form.data.authors[i]['id']" :settings="selectize.authors"></selectize>
selectize: {
authors: {
valueField: 'inn',
labelField: 'name',
searchField: ['name', 'inn'],
options: this.addTrackData.authors // that doesn't works, but hard coded array works
}
}
Because of error Error in data(): "TypeError: Cannot read property 'authors' of undefined".
Both this.addTrackData.authors and addTrackData.authors makes this error.
But this way works:
<selectize v-model="form.data.authors[i]['id']"
:settings=" {
valueField: 'inn',
labelField: 'name',
searchField: ['name', 'inn'],
options: addTrackData.authors, // It works, but looks too ugly!
}" >
</selectize>
2) Options are not reactive - when ajax data comes, all selects elements still shows a demo data. And I have no idea how to update them all...
UPDATE
Second problem could be fixed with If Conditional and empty initial array:
<selectize v-if="addTrackData.authors.length" v-model="form.data.authors[i]['id']"
:settings=" {
valueField: 'inn',
labelField: 'name',
searchField: ['name', 'inn'],
options: addTrackData.authors, // It works, but looks too ugly!
}" >
</selectize>
addTrackData : {
styles : [],
authors: []
....
}
But the first problem still makes me cry
I just read the source code of vue2-selectize and noticed that it's watch code for options key is incorrect.
his code is this way:
watch: {
value() {
this.setValue()
},
options (value, old) {
if (this.$el.selectize && !equal(value, old)) {
this.$el.selectize.clearOptions()
this.$el.selectize.addOption(this.current)
this.$el.selectize.refreshOptions(false)
this.setValue()
}
}
},
while it should be this way to work:
watch: {
value() {
this.setValue()
},
options (value, old) {
if (this.$el.selectize && !equal(value, old)) {
this.$el.selectize.clear();
this.$el.selectize.clearOptions();
var vm = this;
this.$el.selectize.load(function(callback) {
callback(vm.current);
});
this.$el.selectize.refreshOptions(false);
this.setValue();
}
}
},
I just prepared a hacky way to make it working but I dont encourage you using it in production.
Here is the fiddle's link: https://jsfiddle.net/ahmadm/h8p97hm7/
I'll try to send a pull request to his creator as soon as possible but until that time, your solution is already the only possible solution.

AngularJS : Watch array of objects and animate the changed property

I have a $scope collection that is continually being updated through websockets, so data is coming in about every 2 seconds.
Let's say I have this data coming in,
var socketData = [{
name: 'bob',
age: '20',
color: 'red'
}, {
name: 'jack',
age: '10',
color: 'yellow'
}]
$scope.data = socketData;
and it's changing constantly, like this for example, which could happen a number of seconds later.
var socketData = [{
name: 'bob',
age: '21',
color: 'green'
}, {
name: 'sam',
age: '22',
color: 'red'
}]
$scope.data = socketData;
and in the DOM I have this
<div ng-repeat="d in data">
<p>{{d.name}}</p>
<p>{{d.age}}</p>
<p>{{d.color}}</p>
</div>
I would like to animate (by adding a class and just having it fade in) to each property that has changed.
By using $watch, I can get the changes, but only the objects as a whole.
$scope.$watch('data', function(newVal, oldVal) {
console.log(newVal) // whole object
console.log(oldVal) // whole object
}, true);
So the problem is that I dont want to animate the entire object, but rather the property itself. So if the name changed for each object, in the dom I'd like to see the name fields change, not an entire object, just that individual change, and I'm having a difficult time achieving that.

custom angular filter used on ng-option leaves blank options

I am trying to filter out some options in a select element using angular.js. The problem is that for every item in the model that doesn't meet the filter criteria I get a blank option element in the select.
My questions are:
How can I fix the custom filter to remove the empty options?
Is there a way to modify the value of my ng-options directive to perform this filter more declaratively in the markup?
The code is below and you can also find it at http://jsfiddle.net/G4qkW/
<div ng-app="myApp">
<div ng-controller="myController">
<select ng-model="militaryBranches" ng-options="m as m | coreBranches for m in militaryBranches">
<option value="">Select Military Branch</option>
</select>
</div>
function myController($scope) {
$scope.militaryBranches = [{
BranchId: '1',
Name: 'Air Force'
},{
BranchId: '2',
Name: 'Army'
},{
BranchId: '3',
Name: 'Coast Guard'
},{
BranchId: '4',
Name: 'Marines'
},{
BranchId: '5',
Name: 'Navy'
},{
BranchId: '6',
Name: 'National Guard 1'
},{
BranchId: '7',
Name: 'National Guard 2'
},{
BranchId: '8',
Name: 'Some Other Branch'
}];
}
var app = angular.module('myApp', []);
app.filter('coreBranches', function() {
return function(item) {
if (item.BranchId < 6) {
return item.Name;
}
};
});
I have edited your fiddle: http://jsfiddle.net/G4qkW/5/
I guess you want the branches filtered out, not to display their names. You need to apply the filter to the collection, not to the name:
m.BranchId as m.Name for m in militaryBranches | coreBranches
To make this work, edit the filter like this:
app.filter('coreBranches',
function () {
return function (items) {
var filtered = [];
angular.forEach(items, function (item) {
if (item.BranchId < 6) {
filtered.push(item);
}
});
return filtered;
}
});

How to get the id on right click context menu in dojo Tree?

I want to get the node id of Dojo's tree on context menu click.
I'm making a tree in Dojo like this. Here is the id - the first param.
this.setData(
[
{ id: '5', name:'root' , type:'continent' },
{ id: '6', name:'catalog 1', parent: '5' , type:'continent' },
{ id: '7', name:'catalog 2', parent: '5' , type:'continent' },
{ id: '8', name:'catalog 2.1', parent: '7' , type:'continent' },
{ id: '9', name:'child Catalog', parent: '8' , type:'continent' },
{ id: '10', name:'catalog 4', parent: '5' , type:'continent' } ]);
Here is my tree and menu init functions.
So, when I click with the right button on the tree - there is a context menu with a button. When I click that button - it triggers the onClick function. I want to receive that id.
<script>
function createMyTree()
{
var tree = new dijit.Tree({
model: myModel,
id: 'contextMenu'
});
tree.placeAt("myTree", "last");
tree.startup();
pMenu = new dijit.Menu({
targetNodeIds:["contextMenu"]
});
pMenu.addChild(new dijit.MenuItem({
label:"Delete",
iconClass:"dijitEditorIcon dijitEditorIconDelete",
onClick: function(){
/// HERE I WANT MY id
}
}));
pMenu.startup();
}
How can I do that?
I haven't used dojo before, but I think you should use the contextmeu event over onclick. From that you can get the target or relatedTarget and checking it with button property (the type of mouse button pressed; probably 2).
If that doesn't gives you a valid element, you can use document.elementFromPoint(x,y) from the event.screenX and event.screenY to get the valid element.
I found it..
Thanks guys. If you have better suggestions please share it. :)
var selectedObject = tree.get("selectedItems")[0];
console.log("the id what I need", selectedObject.id);
selector: '.dijitTreeNode' in Menu config options.

Categories