Repeating q-select for each item in list and treat selected value for q-select differently for each item of the list - quasar-framework

Basically, I want to repeat q-select/q-tree for each item in the list:
<q-item v-for="item in list">
{{item}}
<q-select
v-model="selected_val"
radio
:options="option"
/>
</q-item>
In data section, I have following code
data(){
return{
list:['item1','item2','item3'],
option:[
{label:'first',value:'first'},
{label:'second',value:'second'},
{label:'third',value:'third'}
],
selected_val:''
}
The current result shown will reflect the value of each item.
i'm using quasar framework with Vue js.

Your selected_val model data should not be a string, but an array.
new Vue({
el: '#q-app',
data(){
return {
list:['item1','item2','item3'],
selected_val: [],
options: [
{label:'first',value:'first'},
{label:'second',value:'second'},
{label:'third',value:'third'}
]
}
}
})
<div id="q-app">
<q-item v-for="(item, index) in list">
<q-item-side>{{item}} </q-item-side>
<q-item-main>
<q-select v-model="selected_val[item]" radio :options="options" />
</q-item-main>
</q-item>
<q-list>
<q-item v-for="item in list"> {{item}} selected value: {{selected_val[item]}}</q-item>
</div>
See codepen for demonstration
Codepen

This is because you are using same v-modal for all the q-select. Each q-select needs to have unique v-modal.
You can achieve this by creating a similar array as list and adding it to v-modal

Related

SAPUI5: How to add custom functionality to column menu of ui.table?

I'd like to give my users the chance to reformat table cells after data has been loaded into the table. I thought a neat way to do this, is adding the functionality to the column menu. So when clicking on a table column, the menu appends with the standard "filtering, sorting" but also has a row called "formatting" which provides a few options (E.g. format a numeric cell from 55555,55 to 55.555,55)
Unfortunately I was unable to find a way to add a new row to my column menu. My sorting and filtering is added like this:
oTable.bindColumns("/columns", function(index, context) {
var columnName = context.getObject().columnId;
return new sap.ui.table.Column({
label:columnName,
template: columnName,
sortProperty: columnName,
filterProperty: columnName,
});
});
How do I add new lines/functionalities to the column menu?
Update
This is how my table looks like in xml view:
<table:Table id="uploadData" visibleRowCountMode="Auto" rowSelectionChange="tableRowSelectionChange" enableCellFilter="true" fixedColumnCount="0" enableBusyIndicator="true" customData="{Type: 'sap.ui.core.CustomData', key:'table-style-type', value:'custom-styled', writeToDom: true }">
<table:extension>
<m:Button icon="sap-icon://download" press="onDataExportXLS" align="Right" />
</table:extension>
<table:columns>
<!-- Columns dynamically created in controller -->
</table:columns>
<table:rows>
<!-- Rows created in controller -->
</table:rows>
</table:Table>
The sap.ui.table.Column has an aggregation called menu just for this. It accepts any custom menu items which are shown when clicking on a Column. This aggregation takes sap.ui.unified.Menu control.
In the select function of the MenuItem aggregation, you can write the function to handle what needs to be done when the menu item is selected
sap.ui.table.Column documentation
sap.ui.unified.Menu documentation
Check it in this sample here and its code here, click on the Quantity column and you will see a My custom menu entry
A snippet of the code here in XML,
<Column id="quantity" width="6rem" hAlign="End" sortProperty="Quantity">
<m:Label text="Quantity" />
<template>
<m:Label text="{ path: 'Quantity', type: 'sap.ui.model.type.Integer'}" />
</template>
<menu>
<u:Menu ariaLabelledBy="quantity">
<u:items>
<u:MenuItem text="My custom menu entry" select="onQuantityCustomItemSelect" />
<u:MenuItem text="Sort" select="onQuantitySort" icon="sap-icon://sort" />
</u:items>
</u:Menu>
</menu>
</Column>
The code in JS,
var oColumn = new sap.ui.table.Column({
label: "Some column Name",
menu: new sap.ui.unified.Menu({
items: [new sap.ui.unified.MenuItem({
text: "My custom menu",
select: function (oEvent) {
pressEventOnItem(oEvent);
})
]
})
})

how to avoid key/id problems in reactjs and make props pass from parent to child?

I keep hitting a wall when trying to get the parent data passed down to the child component.
My view:
<%= react_component 'Items', { data: #items } %>
My Items component makes an ajax call, sets state, and renders Item. Leaving key={this.props.id} out of the Item instance passed into the mapping function makes it so that the component html renders to the page. But add the key in, and I get a console error: Uncaught TypeError: Cannot read property 'id' of undefined
Here's 'Items':
var Items = React.createClass({
loadItemsFromServer: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
cache: false,
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
componentDidMount: function() {
this.loadItemsFromServer();
},
render: function() {
var itemNodes = this.props.data.map(function() {
return (
<Item key={this.props.id} />
);
});
return (
<div className="ui four column doubling stackable grid">
{itemNodes}
</div>
);
}
});
My item.js.jsx component just formats each Item:
var Item = React.createClass({
render: function() {
return (
<div className="item-card">
<div className="image">
</div>
<div className="description">
<div className="artist">{this.props.artist}</div>
</div>
</div>
);
}
});
The React dev tools extension shows the props and state data inside Items. The children, however, are empty.
I'm aware of this, but I'm setting key with this.props.id. I'm not sure what I'm missing?
I found a couple of problems with the code you posted, in the Items component
You're rendering this.props.data while in fact this.state.data is the one being updated with the ajax request. You need to render this.state.data but get the initial value from props
The map iterator function takes an argument representing the current array element, use it to access the properties instead of using this which is undefined
The updated code should look like this
var Item = React.createClass({
render: function() {
return (
<div className="item-card">
<div className="image">
</div>
<div className="description">
<div className="artist">{this.props.artist}</div>
</div>
</div>
);
}
});
var Items = React.createClass({
getInitialState: function() {
return {
// for initial state use the array passed as props,
// or empty array if not passed
data: this.props.data || []
};
},
loadItemsFromServer: function() {
var data = [{
id: 1,
artist: 'abc'
}, {
id: 2,
artist: 'def'
}]
this.setState({
data: data
});
},
componentDidMount: function() {
this.loadItemsFromServer();
},
render: function() {
// use this.state.data not this.props.data,
// since you are updating the state with the result of the ajax request,
// you're not updating the props
var itemNodes = this.state.data.map(function(item) {
// the map iterator function takes an item as a parameter,
// which is the current element of the array (this.state.data),
// use (item) to access properties, not (this)
return (
// use key as item id, and pass all the item properties
// to the Item component with ES6 object spread syntax
<Item key={item.id} {...item} />
);
});
return (
<div className="ui four column doubling stackable grid">
{itemNodes}
</div>
);
}
});
And here is a working example http://codepen.io/Gaafar/pen/EyyGPR?editors=0010
There are a couple of problems with your implementation.
First of all, you need to decide: Do you want to render the #items passed to the Items component from your view? Or do you want to load them asynchronous?
Because right now I get the impression you are trying to do both...
Render items passed from view
If you want to render the items from your view passed to the component, make sure it's proper json. You might need to call 'as_json' on it.
<%= react_component 'Items', { data: #items.as_json } %>
Then, in your Component, map the items to render the <Item /> components. Here is the second problem, regarding your key. You need to define the item variable to the callback function of your map function, and read the id from it:
var itemNodes = this.props.data.map(function(item) {
return (
<Item key={item.id} artist={item.artist} />
);
});
Note, I also added the author as prop, since you are using it in your <Item /> Component.
You can remove your componentDidMount and loadItemsFromServer functions, since you are not using them.
Load items asynchronous
If you want to load the items asynchronously, like you are trying to do in your loadItemsFromServer function, first of all, pass the url from your view and remove the {data: #items} part, since you will load the items from your component, something like:
<%= react_component 'Items', { url: items_path(format: :json) } %>
If you want to render the asynchronous fetched items, use:
var itemNodes = this.state.data.map(function(item) {
return (
<Item key={item.id} artist={item.artist} />
);loadItemsFromServer
});
Note I changed this.props.map to this.state.map
You can now use your componentDidMount and loadItemsFromServer functions to load the data and save them to state.

.Net MVC and Kendo - conditionally bind div based on selected option

I am almost there!
I would like to show a specific div based on the selected value.
For example, if selected value = "Option1" is chosen, then show corresponding div.
I've tried the following in the data-bind:
data-bind="if"selectedValue() === 'Option1'"
I am successfully able to use data-bind="visible" selectedValue" to toggle, but both divs show. I would like to get at the object property itself.
Here's the code:
<select data-bind=", options: availableValues, optionsText: 'Name', value: selectedValue, optionsCaption: 'Select One'"></select>
<div data-bind="if:selectedFieldType() === 'Option1' ">
#Html.Partial("_Edit" + this.Model.Type)
</div>
<div data-bind="if:selectedFieldType() === 'Option2' ">
#Html.Partial("_Add" + this.Model.Type)
</div>
$(function () {
var testModel = {
availableValues: ko.observableArray(#Html.Json(Model.SelectedValueOptions)),
selectedValue: ko.observable(null))
};
testModel.value= ko.dependentObservable(function () {
if (this.selectedValue()) {
return this.selectedValue().Val;
}
}, testModel);
var tryGetValue = $.grep(testModel.availableSelectedValues(), function (item) {
return item.Val === '#Model.Value';
})[0] || null;
testModel.selectedValue(tryGetValue);
ko.applyBindings(testModel, $('#general-section')[0]);
});
Thanks to Artem's comment, I was able to fix it - I was referencing if:value()...and needed to reference the value referenced in the model as opposed to the name I used in the binding parameters (e.g. testModel.value - value was what I needed to reference (in my case that was xyzType as opposed to the generic term "value" that was used in the data-bind options.

jquerymobile not rendering nested listview with knockoutJS

I'm binding a nested listview with knockoutjs and styling it with JQuery mobile like this
<ul id="machine-list" data-bind="foreach: machineList" data-role="listview">
<li><span data-bind="text:location"></span>
<ul data-bind="foreach: machines" data-role="listview">
<li><span data-bind="text:machine"></span></li>
</ul>
</li>
</ul>
When it goes to the nested list there's nothing there. I know the binding is working because if I remove the data-role I get the nested list. Can anyone help? Cheers.
If you're using the latest version of jQuery Mobile, you must know that nested lists have only partial support. Here's the source link.. As mentioned we'll have to use the page -> page navigation system by ourselves, so here goes.
Setup
I built up an example for this sometime back. You could adapt your code to that.
I have a json object array like this :
[
{
"name": "DC Comics",
"characters": [
"All-Star Squadron",
"Birds of Prey",
...
]
},
{
"name": "Marvel Studios",
"characters": [
"Alpha Flight",
"Avengers",
"Champions",
"Defenders",
...
]
}
....
]
So, it might be better if you have two pages, one for showing the main list aka the groups and when clicked, another page to show the sub items ie., the characters.
On page load, I'd like to show something like this :
And when one of those links are clicked, I'd like to show the stuff which is present inside characters array. Like for example, if I choose "DC Comics", the current context would be :
{
"name": "DC Comics",
"characters": [
"All-Star Squadron",
"Birds of Prey",
...
]
}
From here, I'd take out the characters property and show it out in a list in a new page. (This is what nested lists used to do, anyway). So, something like this is what is needed:
Two pages, Two ViewModels
Now to achieve this, there might be ways. But the best method would be to use multiple ViewModels, one for each page, so making it 2 and bind it when that particular page is initialised. So for a particular page,
Markup :
<div data-role="page" id="groups-page"></div>
View Model :
We'd have a seperate ViewModel:
//view model for the parent page.
var groupModel = {
//data array
groupInfo: [
{
"name": "DC Comics",
"characters": [
"All-Star Squadron",
"Birds of Prey",
...
]
},
{
"name": "Marvel Studios",
"characters": [
"Alpha Flight",
"Avengers",
"Champions",
"Defenders",
...
]
}
....
]
}
pageinit event :
And bind it in pageinit event of #group-page:
//events pertaining to Page 1 - the groups
$(document).on({
"pageinit": function () {
//apply partial binding to groups-page alone. Reason we're doing this is because only this page will be available onload
ko.applyBindings(groupModel, this);
}
}, "#groups-page");
Note that the second object in applyBindings (this) indicates the DOM element with id set to groups-page.
Similarly, you'd do the same thing for the second page, #character-page :
Markup :
<div data-role="page" id="character-page"></div>
ViewModel :
//view model for the character page - basically an empty view model to be filled with data when a link is clicked.
var characterModel = {
name: ko.observable(),
characterInfo: ko.observableArray()
}
pageinit event :
//events pertaining to Page 1 - the groups
$(document).on({
"pageinit": function () {
//apply partial binding to character-page alone.
ko.applyBindings(groupModel, this);
}
}, "#character-page");
The reason we're using observables here is because everytime something is clicked, we'd be updating the observables which will automatically change the content of the second page listview.
Populating the first page
This is how my HTML structure looks like :
<ul data-bind="foreach: groupInfo">
<li>
<a href="#">
<span data-bind="text: name"></span>
<span data-bind="text: characters.length" class="ui-li-count"></span>
</a>
</li>
</ul>
And after applyBindings() is bound only to the first page, I'd call a refresh on those listviews in the page :
//apply partial binding to groups-page alone. Reason we're doing this is because only this page will be available onload
ko.applyBindings(groupModel, this);
//refresh the listview
$("ul", this).attr("data-role", "listview").listview().listview("refresh");
This would lie in the pageinit event of the #group-page.
Click event of the groups, changePage to characters
For this, I'd use the click binding of KO on the a tag of the listview in first page:
<a href="#" data-bind="click: $root.getInfo">
<span data-bind="text: name"></span>
<span data-bind="text: characters.length" class="ui-li-count"></span>
</a>
where $root is the context in ViewModel level (see docs).
Oh wait! getInfo must be added to groupModel, the model for the first page. So the viewmodel is changed to this :
//view model for the parent page.
var groupModel = {
//data array
groupInfo: [
//groups
],
//click event to be fired when an anchor tag is clicked
getInfo: function (data, e) {
//here "data" variable gives the clicked elements' corresponding array and "e" gives the event object
//prevents defaultbehaviour of anchor tag
e.preventDefault();
//setting up the character array in View model of page 2
characterModel.characterInfo(data.characters);
//setting up name variable of ViewModel in page 2
characterModel.name(data.name);
//change the page
$.mobile.changePage("#character-page", {
transition: "slide"
});
}
}
Note that I'm populating the characterModel only now. Since the properties inside this model are observables, every time these variables are updated, DOM is also updated. The HTML of the second page is :
<ul data-bind="foreach: characterInfo">
<li data-bind="text: $data"></li>
</ul>
$data is used to get the stuff inside characterInfo, if you didn't know. When this is done, you'd have something like this :
The next step would be to refresh the listview, but not in pageinit. Reason being, pageinit is fired only once and since character-page gets updated every single time a click happens, you'd have use a pageshow or pagebeforshow method. More info here. Now the events bound to the character-page are :
//events pertaining to Page 2 - the characters
$(document).on({
"pageinit": function () {
ko.applyBindings(characterModel, this);
},
"pagebeforeshow": function () {
//refresh listview before page is shown
$("ul", this).attr("data-role", "listview").listview().listview("refresh");
}
}, "#character-page");
The above snip would refresh your styles everytime the pagebeforeshow event of "#character-page" is triggered (which is what we want) and finally give you this :
So that's it! Hope this helped :)
And, before we forget, here's a demo.

Optimal way to save order of jQueryUI sortable list with Meteor

I need some guidance/suggestions for an optimal way to save the order of a sortable list that takes advantage of Meteor.
The following is a scaled down version of what I'm trying to do. The application is a simple todo list. The end goal for the user is to sort their list where the data is picked up from the database. As the user sorts tasks, I would like to save the order of the tasks.
I've implemented this application without Meteor using php/ajax calls using sortable's update event that would delete the entry in the database and replace it with what was currently in the DOM. I'm curious to know if there are a better ways to do this taking advantage of Meteor's capabilities.
The following sample code is straight off of a live demo.
HTML:
<template name="todo_list">
<div class="todo_list sortable">
{{#each task}}
<div class="task">
<h1>{{title}}</h1>
{{description}}
</div>
{{/each}}
</div>
</template>
JS(Without the Meteor.isServer that simply populates the database.):
if (Meteor.isClient) {
//Populate the template
Template.todo_list.task = function () {
return Tasks.find({});
};
//Add sortable functionality
Template.todo_list.rendered = function () {
$( ".sortable" ).sortable();
$( ".sortable" ).disableSelection();
};
}
Sample data (Output of Tasks.find({})):
[{
title:"CSC209",
description:"Assignment 3"
},
{
title:"Laundry",
description:"Whites"
},
{
title:"Clean",
description:"Bathroom"
}]
You'd probably want to first sort your items by a new field on you collection then, you'll want to hook into the jQuery sortable update event:
if (Meteor.isClient) {
// Populate the template
Template.todo_list.task = function () {
return Tasks.find({}, { sort: ['order'] });
};
// Add sortable functionality
Template.todo_list.rendered = function () {
$('.sortable').sortable({
update: function (event, ui) {
// save your new list order based on the `data-id`.
// when you save the items, make sure it updates their
// order based on their index in the list.
some_magic_ordering_function()
}
});
$( ".sortable" ).disableSelection();
};
}
You template would look a bit like this:
<template name="todo_list">
<div class="todo_list sortable">
{{#each task}}
<div class="task" data-id="{{_id}}">
<h1>{{title}}</h1>
{{description}}
</div>
{{/each}}
</div>
</template>
And when that event is triggered, it would determine the order of the list and save the new order in the documents for the collection.
This isn't really a complete answer, but hopefully it helps a bit.

Resources