I would like to know if I could change select options using Angular-Formly depending on another select's selected value.
Lets say I have beverageTypeSelect and drinkSelect.
beverageTypeSelect has options Alcoholic and Non-Alcoholic.
drinkSelect would have Heineken, Budweiser, Alcohol 96%, if beverageTypeSelect value is Alcoholic.
drinkSelect would have Coca-Cola, Pepsi, Water, if beverageTypeSelect value is Non-Alcoholic.
How can I do that?
Editing:
Ok, let's try to make it a little more clear:
This is not my real application, but I want to keep it simple and get the general solution for this, so I'll keep with the beverage.
We are using https://github.com/formly-js/angular-formly-templates-bootstrap.
We have a formly forms generator. The part of code that is interesting in here is this:
if (obj.ngOptions){
o.templateOptions.options=[];
o.templateOptions.ngOptions = obj.ngOptions;
}
We have figured out that options must by an empty array so ngOptions can take place.
So we have a formly form like this:
[{
key: 'beverageTypeSelect',
type: 'select',
templateOptions: {
options: [{
name: 'Alcoholic',
value: 'A'
},
{
name: 'Non-Alcoholic',
value: 'N'
}]
}
}, {
key: 'drinkSelect',
type: 'select',
templateOptions: {
options: [],
ngOptions: 'item as item.label for item in model.drinkSelect track by item.id'
}]
Then we'll have a html to show our form:
<formly-form fields="formFields" model="DrinkingCtrl.data" form="DrinkingCtrl.form">
</formly-form>
And, finally, our controller:
'use strict'
angular.module('drunkApp')
.controller('DrinkingCtrl', drinking);
function drinking($scope, $stateParams, $state, $reactive, AutoSaveReactiveFormScope) {
var self = this;
var vm = AutoSaveReactiveFormScope($scope, this, 'NAME_TO_SEARCH_FOR_DRINK_FORMLY_FORM', 'drinkPublishName', drinkMongoCollection, $stateParams.id); // This is a factory that gives us everything (or almost it) that we need in a controller with form autosave functionallity :).
var drinkOptions = [{
id: 'H',
label: 'Heineken',
types: ['A']
}, {
id: 'B',
label: 'Budweiser',
types: ['A']
}, {
id: 'A',
label: 'Alcohol 96%',
types: ['A']
}, {
id: 'C',
label: 'Coca-Cola',
types: ['N']
}, {
id: 'P',
label: 'Pepsi',
types: ['N']
}, {
id: 'W',
label: 'Water',
types: ['N']
}];
vm.autorun(function() {
if (self.data) {
self.data.drinkSelect = _.filter(drinkOptions, function(drk) {
return _.contains(drk.types, self.data.beverageTypeSelect);
});
}
});
}
This really works, but I was expecting something cleaner, something that I could do directly inside of the form declaration. Maybe do something like we can do with required or hideExpression (that we can write something like 'model.option1 != "BLA"' or a function).
p.s.: Hope this time I made myself clearer.
Related
I'm trying to populate possible dropdown options on vue good table. The idea is that I conduct an API call to the server to bring back what values can possibly go into the drop down and I'm trying to assign it to the column filter. However, I can't seem to get it to work.
<vue-good-table
:paginationOptions="paginationOptions"
:sort-options="sortOptions"
:isLoading.sync="isTableLoading"
:rows="rows"
:columns="columns"
:lineNumbers="true"
mode="remote"
:totalRows="totalRecords"
#on-row-click="onRowClick"
#on-page-change="onPageChange"
#on-sort-change="onSortChange"
#on-column-filter="onColumnFilter"
#on-per-page-change="onPerPageChange"
#on-search="onSearch"
:search-options="{
enabled: true
}"
styleClass="vgt-table striped bordered"
ref="table"
>
Fairly standard vgt set up.
columns: [
{
label: 'some column',
field: 'column1'
},
{
label: 'Customer',
field: 'customerName',
filterOptions: {
enabled: true,
placeholder: 'All',
filterDropdownItems: Object.values(this.customers)
}
},
{
label: 'other columns',
field: 'column234'
}
]
and the API call
methods: {
async load () {
await this.getTableOptions()
},
async getTableOptions () {
try {
var response = await axios.get(APICallUrl)
this.customers= []
for (var i = 0; i < response.data.customers.length; i++) {
this.customers.push({ value: response.data.customers[i].customerId, text: response.data.customers[i].customerName})
}
} catch (e) {
console.log('e', e)
}
}
The only thing that I thought of is that the table has finished rendering before the load method is complete. However just creating a static object in my data and assigning it to a filterDropDownItems yielded no better results. The result whenever I try to set it to an object is that the box is a type-in box rather than a dropdown.
You can make the table update after it's rendered by making columns a computed property. The other problem you have is this.customers is an Array but Object.values() expects an Object. You could use the Array.map function instead
this.customers.map(c => c.value)
Although according to the VueGoodTable docs an array of objects like you have should work just fine
computed: {
columns() {
return [
{
label: 'some column',
field: 'column1'
},
{
label: 'Customer',
field: 'customerName',
filterOptions: {
enabled: true,
placeholder: 'All',
filterDropdownItems: this.customers
}
},
{
label: 'other columns',
field: 'column234'
}
];
}
}
I want to add some styles to more than one block type.
At the moment I'm doing this for every block type like this and change only the part 'core/paragraph' to 'core/heading' for example.
Is there any way to do this for more than one block at the same time?
wp.blocks.registerBlockStyle(
'core/paragraph',
[
{
name: 'default',
label: 'Default',
isDefault: true,
},
{
name: 'lead',
label: 'Lead',
},
{
name: 'subline',
label: 'Subline',
},
]
);
If you know names of the blocks you want to add your styles to, you can use registerBlockStyle() in a forEach() loop to mass register multiple styles to multiple blocks, eg:
const blocks = ["core/quote", "core/heading", "core/paragraph"]; //etc..
const styles = [
{
name: 'default',
label: 'Default',
isDefault: true,
},
{
name: 'lead',
label: 'Lead',
},
{
name: 'subline',
label: 'Subline',
}
];
// Loop through each block and register all custom styles in one go..
blocks.forEach(function(blocks) {
wp.blocks.registerBlockStyle(blocks, [...styles]);
});
To find the names of all currently registered blocks, use:
wp.blocks.getBlockTypes().map(block => block.name);
Even though you could apply your styles to every block, please use it sparingly only on required blocks - not every block all at once..
I have created a simple component that displays a SELECT tag. On making a selection, I want to pass the selected value to parent (Vue). This is the component code:
// Period Selection
Vue.component ('period-component', {
props: [],
data () {
return {
periods: [
{ text: '-- Select --', value: ''},
{ text: 'Today', value: 'Today'},
{ text: 'Up to Last 7 Days', value: '7D'},
{ text: 'Up to Last 30 Days', value: '30D'},
{ text: 'Up to 3 Months', value: '3M'},
{ text: 'Up to 6 Months', value: '6M'},
{ text: 'Up to 1 Year', value: '1Y'},
{ text: 'All', value: '1Y'},
],
selectedPeriod:false,
}
},
methods: {
periodChanged() {
console.log('In periodChanged.' ,this.selectedPeriod);
this.$emit('periodChangedEvent', this.selectedPeriod);
},
},
template: `<div>
<select
v-model="selectedPeriod"
v-on:change="periodChanged()">
<option
v-for="period in periods"
:value="period.value">{{ period.text }}
</option>
</select>
</div> `
})
I use the component in the folloing way:
<period-component
v-on:periodChangedEvent="selectedPeriodChanged($event)" >
</period-component>
In the vue object, I have the selectedPeriodChanged() method like this.
selectedPeriodChanged: function(value){
console.log('in periodChanged' );
},
When I make selection in , the periodChanged() method fires and I get the selected value in component's selectedPeriod. However, I am unable to emit the event to the parent. (Parent's selectedPeriodChanged() never fires) I don't see any errors. What's wrong in my code? Thanks.
Because HTML attributes are case insensitive, the event name should be kebab-case in the template instead of camelCase. See: https://v2.vuejs.org/v2/guide/components.html#camelCase-vs-kebab-case
<period-component v-on:period-change-event="selectedPeriodChanged($event)"></period-component>
this.$emit('period-change-event', this.selectedPeriod);
Here is a working fiddle
I wanted to update my model using $filter or some other smart way without having to do multiple for each.
So basically I have my model similar to below:
$scope.projects = [
{
tasks: [
{
name: 'task name',
visible: true,
starred: true
}
],
createdAt: 'something'
},
{
tasks: [
{
name: 'second task name',
visible: true,
starred: false
}
],
createdAt: 'something'
}
]
What I wanted to do is by using $filter or some other way like underscore and so on, to update the content of the variable. So for instance, when I click a button, I'd like to set visible = true only to tasks that are starred.
Anyone have a suggestion on how to achieve that? Is it possible or I would have to do a couple of loops?
Something like:
$filter('filter')($scope.projects, {{starred = true}}).tasks.visible = true
UPDATE
With the help from #jbrown I was able to achieve what I wanted.
Just in case someone needs similar approach, the final solution was as written below:
_.forEach($scope.projectsModel.projects, function(proj){
_.forEach(_.filter(proj.tasks, {starred: true}), function(task){
task.visible = true;
});
});
Using underscore you can use a combination of filter and find to get the results you are looking for.
$scope.filteredProjects = _.filter($scope.projects, function(proj) {
return _.find(proj.tasks, {
visible: true, starred: true });
});
I'm using the jquery autocomplete plugin and I am comming up to a few problems:
I have a lot of data and when I type data a long suggestion list is shown and a scrollbar is needed:
$("#txtName").autocomplete(data,
{ matchContains: true,
minChars: 0,
max: 3000,
scroll: true,
//scrollHeight: 180,
width: 200
});
but, the scrollbar does't work properly in IE (it's a known issue, I searched alot but have'nt found a relevant solution).
so I decided to block the suggestion list popup and get the suggestion list results into an array or somthing similar and show them in my control.
my problem is - How do I get that list?
Thanks in advance!
Quickly looking through that Plugin's API, I don't see any events that let you handle the response from a server call-back. You may want to switch and use the official JQuery UI library for your auto-completing needs. There is an appendTo option that might suit your need.
I found the answer (part of it, I still need to work on it).
I'll first post the code and then explain it:
$(function ()
{
var names = [
{ label: 'Java', value: '1' },
{ label: 'C++', value: '2' },
{ label: 'C#', value: '3' },
{ label: 'Jquery', value: '4' },
{ label: 'Javascript', value: '5' },
{ label: 'ASP', value: '6' },
{ label: 'Pearl', value: '7' },
{ label: 'VB', value: '8' },
{ label: 'Ajax', value: '9' },
{ label: 'Json', value: '10' }];
$("#txtName").autocomplete({
minLength: 2,
source: names,
delay: 500
}).data("autocomplete")._renderItem = function (ul, item)
{
//add data to my control, need to take care of earasing each time.
var elOptNew = document.createElement('option');
elOptNew.text = item.label;
elOptNew.value = item.value;
lst.add(elOptNew);
//this code here adds the items to the popup thats built in.(it's written in jquery-ui.min.js)
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a>" + item.label + "</a>")
.appendTo(ul);
};
});
Html:
<input id="txtName"/>
<select id="lst" size='10'></select>
The added part (_renderItem) adds one item each time, so you can do whatever you want to do with an item. I decided to add it to a list.
The other thing that's not done is erasing the list each time. I still need to figure out how to do that.