I want to submit to the server the ID of the selected fixtures but I don't know how.
I have to display an object (that I'm passing in props) in a select menu.
In my select menu I have:
v-select
v-model="form.array"
:items="array"
item-text="name"
item-value="id"
label="Select"
outlined
dense
multiple
chips
return-object
></v-select>
and My form is
data() {
return {
form: Object.assign({}, defaultForm),
valid: true,
defaultForm,
dialog: null,
counterOfUnnamed: '',
checkbox: true,
You can filter the fixtures first and then filter the id property from the filtered array
Here is the working code, it works perfectly
var self = this;
self.fixtures.filter(fixture => self.form.selectedFixture.map(x => x.id).includes(fixture.id)).map(fixture => fixture.id)
In your code add this inside your submit function, dont rewrite the existing this.form.selectedFixture, just craete a new variable assign to it and use then
submit() {
var self = this;
const selectedFixture = self.fixtures.filter(fixture => self.form.selectedFixture.map(x => x.id).includes(fixture.id)).map(fixture => fixture.id);
console.log(selectedFixture);
http.post('group/create', {
name: this.form.groupName,
fixtures: selectedFixture
}).then(result => {
this.groups.push(result);
}).catch(error => {
console.log((error));
});
this.resetForm();
},
Related
I want to help the user author handlebars/mustache templates so when they type a { character, an autocomplete of known template values comes up to assist the user. But the user may not want to choose one of the suggested options, they might just want to continue typing a new template value and terminate it with a }. In the example in the code below, the options "Order Number" and "Delivery Date" are the known autocomplete options, but I want the user to be able to type {Invoice Number} for example.
I've succeeded in make this work in one way. As a user is typing {Invoice Number} I add it to the list of allowed options in the autocompleter fetch function. So the user can get what they want into the document if the click on the suggested option. Clicking fires the onAction function. I want onAction to fire as soon as the user types the closing handlebars character i.e. }.
Here is the code I have tried. I am using TinyMCE 5.
let template = (function () {
'use strict';
tinymce.PluginManager.add("template", function (editor, url) {
const properties = [
{value: "Order Number", text: "Order Number"},
{value: "Delivery Date", text: "Delivery Date"}
];
const insertNewProperty = function(value) {
let property = {value: value, text: value};
properties.push(property);
return property;
};
editor.ui.registry.addAutocompleter('autocompleter-template', {
ch: '{',
minChars: 0,
columns: 1,
fetch: function (pattern) {
return new tinymce.util.Promise(function (resolve) {
let filteredProperties = pattern ? properties.filter(p => p.text.indexOf(pattern) > -1) : properties;
if (filteredProperties.length > 0) {
resolve(filteredProperties);
} else {
resolve([{value: pattern, text: pattern}]);
}
});
},
onAction: function (autocompleteApi, rng, value) {
let property = properties.find(p => p.value === value);
if (!property) {
property = insertNewProperty(value)
}
let content = `{${property.text}}`;
editor.selection.setRng(rng);
editor.insertContent(content);
autocompleteApi.hide();
}
});
return {
getMetadata: function () {
return {
name: "Learning",
url: "https://stackoverflow.com"
};
}
};
});
}());
})();```
You can add a matches function to your callbacks, along with your onAction, this help you do it.
matches: function (rng, text, pattern) {
if(pattern.endsWith('}')){
pattern = pattern.replace('}', '');
/**
* Check if pattern does not match an existing
* variable and do what you want
*/
return true;
}
},
And make sure the function always returns true.
Very new to Vue2, so far so good but I hit a little snag and front end is not my forte.
The table(vue-tables-2) displays correctly what's in the database. I am passing an id in a function to determine what particular row to update but I also want to update the value of the checkbox in the database whenever I press it. How can I achieve that? Many thanks.
<v-client-table :data="tableData" :columns="columns" :options="options" >
<input type="checkbox" v-model="props.row.powerOff" #change="powerOff(props.row.id, props.row.powerOff)">
</v-client-table>
export default {
data() {
return {
columns: ['id', 'name', 'location.address', 'status', 'payment', 'powerOff'],
tableData: []
}
},
created() {
HTTP.get('test').then( response => {this.tableData = response.data;})
.catch( error => {});
},
methods: {
powerOff(id, currentPowerOff) {
var testURL = 'test/' + id
HTTP.patch(testURL, {id, currentPowerOff})//
.then( response => {})
.catch( error => {console.log(error); });
}
}
}
It seems that changing from v-click:on to #change fixed my issue. Reading a little bit more about it, click event is run before v-model has updated the value, while #change does it afterwards. Thank you !
Say I have a list of models:
const documents = [{}, {}, {}];
And I want to insert these into the DB, or update them all, but only if a condition is met:
Model.update({isSubscribed: {$ne: false}}, documents, {upsert:true},(err, result) => {
});
The above signature is surely wrong - what I want to do is insert/update the documents, where the condition is met.
There is this Bulk API:
https://docs.mongodb.com/manual/reference/method/Bulk.find.upsert/
but I can't tell if it will work when inserting multiple documents.
Imagine this scenario: We have a list of employees and a form of some sorts to give them all a penalty, at once, not one by one :)
On the backend side, you would have your eg addBulk function. Something like this:
Penalty controller
module.exports = {
addBulk: (req, res) => {
const body = req.body;
for (const item of body) {
Penalty.create(item).exec((err, response) => {
if (err) {
res.serverError(err);
return;
}
});
res.ok('Penalties added successfully');
}
}
Then you'll probably have an API on your frontend that directs to that route and specific function (endpoint):
penaltyApi
import axios from 'axios';
import {baseApiUrl} from '../config';
const penaltyApi = baseApiUrl + 'penalty'
class PenaltyApi {
static addBulk(penalties) {
return axios({
method: 'post',
url: penaltyApi + '/addBulk',
data: penalties
})
}
}
export default PenaltyApi;
...and now let's make a form and some helper functions. I'll be using React for demonstration, but it's all JS by the end of the day, right :)
// Lets first add penalties to our local state:
addPenalty = (event) => {
event.preventDefault();
let penalty = {
amount: this.state.penaltyForm.amount,
unit: this.state.penaltyForm.unit,
date: new Date(),
description: this.state.penaltyForm.description,
employee: this.state.penaltyForm.employee.value
};
this.setState(prevState => ({
penalties: [...prevState.penalties, penalty]
}));
}
Here we are mapping over our formData and returning the value and passing it to our saveBulkEmployees() function
save = () => {
let penaltiesData = Object.assign([], this.state.penalties);
penaltiesData.map(penal => {
penal.employeeId = penal.employee.id;
delete penal.employee;
return penaltiesData;
});
this.saveBulkEmployees(penaltiesData);
}
...and finally, let's save all of them at once to our database using the Bulk API
saveBulkEmployees = (data) => {
PenaltyApi.addBulk(data).then(response => {
this.success();
console.log(response.config.data)
this.resetFormAndPenaltiesList()
}).catch(error => {
console.log('error while adding multiple penalties', error);
throw(error);
})
}
So, the short answer is YES, you can absolutely do that. The longer answer is above :) I hope this was helpful to you. If any questions, please let me know, I'll try to answer them as soon as I can.
I have a sap.ui.table.Table whose selectionMode is Single and selectionBehavior is RowOnly.
I want to select a row programmatically based on content;
There is code to select by index like
table.setSelectedIndex()
table.setSelectionInterval()
but I am not able to get the index of the content, whose row is to be selected.
Is there any other way?
As commented in the question, there is currently no straightforward solution to select row(s) programmatically by content. But I read:
I want an answer that works. Best practices/ suggestions are not accepted.
If that's still the case, I assume you're ok with accessing internal properties. The only internal property I'm using is the aKeys from the ODataListBinding instance. The following snippets are from this example: https://embed.plnkr.co/7lcVJOaYsnIMJO1w [1]
Single Select
<Table xmlns="sap.ui.table"
id="myGridTable"
selectionMode="Single"
selectionBehavior="RowOnly"
rows="{
path: '/Customers',
events: {
change: '.onRowsDataChange'
}
}"
>
<!-- columns -->
</Table>
Controller.extend("demo.controller.TableSingleSelect", {
onRowsDataChange: function(event) {
this.selectCustomer(/*your key part(s) e.g.:*/ "ANTON"/*, ...*/);
},
selectCustomer: function(customerId/*, ...*/) {
const rowsBinding = this.byId("myGridTable").getBinding("rows");
this.selectIndexByKey(rowsBinding.getModel().createKey("Customers", {
CustomerID: customerId,
//...
}), rowsBinding.aKeys);
},
selectIndexByKey: function(targetKey, keys) {
const table = this.byId("myGridTable");
const index = +Object.keys(keys).find(key => targetKey === keys[key]);
const shouldSelect = index > -1 && !table.isIndexSelected(index);
return shouldSelect ? table.setSelectedIndex(index) : table;
},
});
Multi Select
<Table xmlns="sap.ui.table"
id="myGridTable"
selectionMode="MultiToggle"
rows="{
path: '/Orders',
events: {
change: '.onRowsDataChange'
}
}"
>
<!-- columns -->
</Table>
Controller.extend("demo.controller.TableMultiSelect", {
onRowsDataChange: function(event) {
const value1 = new Date("1996"); // 1996-01-01
const value2 = new Date("1997"); // 1997-01-01
this.selectOrdersBy("OrderDate", "BT", value1, value2);
},
selectOrdersBy: function(propertyName, filterOperator, value1, value2) {
const table = this.byId("myGridTable").clearSelection();
const keys = table.getBinding("rows").aKeys;
const loadedContexts = this.getLoadedContexts(keys, table, "rows");
const filteredContexts = FilterProcessor.apply(loadedContexts, [
new Filter(propertyName, filterOperator, value1, value2),
], (context, path) => context && context.getProperty(path));
this.selectIndices(keys, filteredContexts, table);
},
getLoadedContexts: function(keys, control, aggregationName) {
const model = control.getBinding(aggregationName).getModel();
const parameters = control.getBindingInfo(aggregationName).parameters;
return keys.map(key => model.createBindingContext(`/${key}`, parameters));
},
selectIndices: (keys, contexts, table) => Object.keys(keys).map(index => +index)
.filter(i => contexts.find(context => `/${keys[i]}` == context.getPath()))
.map(i => table.isIndexSelected(i) || table.addSelectionInterval(i, i)),
});
* FilterProcessor is a private module.
The internal property aKeys consists of keys, from loaded contexts, with indices reflecting the table row indices. E.g.: If the table has 3 rows loaded and I call table.getContextByIndex(90), the aKeys will be:
0: "Customers('ALFKI')"
1: "Customers('ANATR')"
2: "Customers('ANTON')"
90: "Customers('WOLZA')"
The change handler onRowsDataChange is fired on any ChangeReason. This keeps the selection from being removed whatever happens to the table rows, be it sorting, filtering, refreshing, etc..
[1]: The samples in this answer work with an ODataModel. In case of a client-side JSONModel, take a look at this answer: stackoverflow.com/a/52664812.
Depending on your design you can for instance use a button receive the selected index:
oEvent.getSource().getParent().getIndex()
example
This small piece of code did the work for me. Table is bound to JSONModel.
const rowsBinding = oTable.getBinding("rows");
var index1 = -1;
rowsBinding.oList.find(function(element){
index1++;
if(element.yourField== "your Content")
{
oTable.setSelectedIndex(index1);
}
});
Now i am able select my row on the basis of content.
JSONModel
There was another request to do it with a JSONModel. So here it is.
The following snippets are from https://embed.plnkr.co/xuSU3uH1rkXmEAV7:
<Table xmlns="sap.ui.table"
id="myGridTable"
selectionMode="Single"
selectionBehavior="RowOnly"
rows="{
path: '/Customers',
events: {
change: '.onRowsDataChange'
}
}"
>
<!-- columns -->
</Table>
Controller.extend("demo.controller.TableSingleSelect", {
onRowsDataChange: function(event) {
this.selectWhere(context => context.getProperty("CustomerID") == "ANTON" /*&& ...*/);
},
selectWhere: function(keysAreMatching) {
const table = this.byId("myGridTable");
const contexts = table.getBinding("rows").getContexts();
const index = this.getRowIndexWhere(keysAreMatching, contexts);
return this.selectRowByIndex(index, table);
},
getRowIndexWhere: function(keysAreMatching, contexts) {
let index = -1;
contexts.find((context, i) => keysAreMatching(context) && (index = i));
return index;
},
selectRowByIndex: function(i, table) {
const shouldSelect = i > -1 && !table.isIndexSelected(i);
return shouldSelect ? setTimeout(() => table.setSelectedIndex(i)) : table;
},
});
With a client-side model like JSONModel, it is a bit easier to find certain row(s) than with server-side models since all necessary data are locally available via rowsBinding.getContexts(). The returned contexts are assigned to the indices corresponding to table's row indices.
So I'm just learning Angular and I have basic routing setup and a partial for setting up a basic page with a form (theoretically any form), and based on the controller I load it loads that form from a fields array in the controller.
One of those forms is a registration form where I want to verify that the passwords match.
So in the partial I have (a mode complicated version of) this
<input ng-repeat="field in fields" ng-model="field.model" mustEqual="fields.mustEqual">
I found a directive which does password comparison:
taskDivApp.directive('mustEqual', function() {
return {
restrict: 'A', // only activate on element attribute
require: '?ngModel', // get a hold of NgModelController
link: function(scope, elem, attrs, ngModel)
{
if(!ngModel) return; // do nothing if no ng-model
// watch own value and re-validate on change
scope.$watch(attrs.ngModel, function()
{
validate();
});
// observe the other value and re-validate on change
attrs.$observe('equals', function (val)
{
validate();
});
var validate = function()
{
// values
var val1 = ngModel.$viewValue;
var val2 = attrs.mustEqual;
// set validity
ngModel.$setValidity('equals', val1 === val2);
};
}
}
});
So basically all I want to do is be able to load a literal string into ng-model from the controller so that I can pair up the model and the must equal, so the data for the form would look like:
$scope.fields = [
{
'type':"Email",
'placeholder':"Email Address",
'req': true,
'focus':true
},
{
'type':"Password",
'placeholder':"Password",
'model': "password",
'mustEqual': "passwordConf"
},
{
'type':"Password",
'placeholder':"Comfirm Password",
'model':"passwordConf",
'mustEqual': "password"
}
];
However what happens now is that the main password field gets bound to the "model" field of its index in the array and similar for passwordConf (ie inital values literally "password" and "passwordConf")
The fact that this isn't easy makes me think I have the wrong mindset - is this not a good way to do forms, should I just have them hard coded?
If this is okay then any ideas on how I could accomplish it would be appreciated!