yeoman generator : repeat a prompt - generator

i'm create a custom yeoman generator, i need create an array base on user responses :
How can i repeat a question and push answer to an array ?
ex :
Add a value ? Y/n
if yes
Value = ?
Add a value ? Y/n
...
for the moment, i have this code :
MyGenerator.prototype.askFor = function askFor() {
var cb = this.async();
console.log(this.yeoman);
var prompts = [
{
type: 'confirm',
name: 'addvalue',
message: 'Add value ?',
default: true
},
{
name: 'myarray',
message: 'Value =',
}
];
this.prompt(prompts, function (props) {
this.addvalue = props.addvalue;
cb();
}.bind(this));
};

Just use a recursive function.
example (won't work as is because of this context):
function askSomething() {
this.prompt({ /* some prompts */ }, function (answers) {
// call the function back if needed
askSomething();
});
}

Related

Merge mixin in vue

I'm working in vue/quasar application.
I've my mixin like this in my view.cshtml
var mixin1 = {
data: function () {
return { data1:0,data2:'' }
}
,
beforeCreate: async function () {
...}
},
methods: {
addformulaire(url) {
},
Kilometrique() { }
}
}
And I want merge with my content in js file (it's to centralize same action an severals cshtml)
const nomeMixins = {
data: function () {
return { loadingcdt: false, lstclt: [], filterclient: [], loadingdoc: false, lstdoc: [], filterdoc: [] }
},
computed: {
libmntpiece(v) { return "toto"; }
},
methods: {
findinfcomplemtX3(cdecltx3, cdedocx3) {
},
preremplissagex3: async function (cdecltx3, cdedocx3) {
}
}
}
};
I want merge this 2 miwin in one. But when I try assign or var mixin = { ...mixin1, ...nomeMixins };
I've only mixin1 nothing about methods,data from my js file nomeMixins but merging failed cause I've same key in my json object. I'm trying to make a foreach but failed too
Someone try to merge to mixin / json object with same key in the case you've no double child property ?
You cant merge mixins in that way. the spread syntax will overwrite keys e.g data, computed, methods etc and final result will not be suitable for your purpose.
refer documentation for adding mixins in your component. Also note that You can easily add multiple mixins in any component, so I don't think combination of two mixins will be any useful.
UPDATE
reply to YannickIngenierie answer and pointing out mistakes in this article
Global Mixins are not declared like this
// not global mixin; on contrary MyMixin is local
// and only available in one component.
new Vue({
el: '#demo',
mixins: [MyMixin]
});
Local Mixins are not declared like this
// NOT local mixin; on contrary its global Mixin
// and available to all components
const DataLoader = Vue.mixin({....}}
Vue.component("article-card", {
mixins: [DataLoader], // no need of this
template: "#article-card-template",
created() {
this.load("https://jsonplaceholder.typicode.com/posts/1")
}
});
Point is refer documentation first before reading any article written by some random guy, including me. Do slight comparison what he is saying whats in documentation.
After working and searching... I find this one And understand that I can add directly mixin in my compoment (don't laught I'm begging with vue few months ago)
my custommiwin.js
const DataLoader = Vue.mixin({
data: function () {
return { loadingcdt: false, lstclt: [], filterclient: [], loadingdoc: false, lstdoc: [], filterdoc: [] }
},
methods: {
filterClt: async function (val, update, abort) {
if (val.length < 3) { abort(); return; }
else {//recherche
this.loadingcdt = true;
let res = await axios...
this.loadingcdt = false;
}
update(() => {
const needle = val.toLowerCase();
this.filterclient = this.lstclt.filter(v => v.libelle.toLowerCase().indexOf(needle) > -1 || v.id.toLowerCase().indexOf(needle) > -1);
})
},
filterDocument: async function (val, update, abort, cdecltx3) {
if (!cdecltx3 || val.length < 3) { abort(); return; }
else {//recherche
this.loadingdoc = true;
let res = await axios({ ...) }
this.loadingdoc = false;
}
update(() => {
const needle = val.toLowerCase();
this.filterdoc = this.lstdoc.filter(v => v.id.toLowerCase().indexOf(needle) > -1);
})
},
}
});
and in my compoment.js I add this
mixins: [DataLoader],
I include all my js file in my cshtml file

Create keyed Maps from nested Lists with Immutable.js

I am working with a dataset that cannot be modified on the server side. So I am trying to setup the local data model on the client in a way that I can easily traverse through the model when updating parts of the data.
Therefore I am trying to create a multi-leveled Map from multi-leveled Maps including Lists, that themselves include Maps, etc. (see schematics at the end of this post).
What I am trying to get is a Map containing other Maps, with the key of the included Map being the value of the object (again please see schematics at the end of this post).
I got it to work on the first level:
const firstLevel = data.toMap().mapKeys((key, value) => value.get('value'));
See it in action here: https://jsfiddle.net/9f0djcb0/4/
But there is a maximum of 3 levels of nested data and I can't get my head around how to get the transformation done. Any help appreciated!
The schematic datasets:
// This is what I got
const dataset = [
{
field: 'lorem',
value: 'ipsum',
more: [
{
field: 'lorem_lvl1',
value: 'ispum_lvl1',
more: [
{
field: 'lorem_lvl2',
value: 'ispum_lvl2',
more: [
{
field: 'lorem_lvl3',
value: 'ispum_lvl3',
}
]
}
]
}
]
},
{
field: 'glorem',
value: 'blipsum'
},
{
field: 'halorem',
value: 'halipsum'
}
];
This is where I want to go:
// This is what I want
const dataset_wanted = {
ipsum: {
field: 'lorem',
value: 'ipsum',
more: {
lorem_lvl1: {
field: 'lorem_lvl1',
value: 'ispum_lvl1',
more: {
lorem_lvl2: {
field: 'lorem_lvl2',
value: 'ispum_lvl2',
more: {
lorem_lvl3: {
field: 'lorem_lvl3',
value: 'ispum_lvl3',
}
}
}
}
}
}
},
glorem: {
field: 'glorem',
value: 'blipsum'
},
halorem: {
field: 'halorem',
value: 'halipsum'
}
};
Retrieve nested structures using "getIn" is beter.
const data = Immutable.fromJS(dataset[0]);
const firstLevel = data.getIn(['more']);
const twoLevel = firstLevel.getIn([0,'more']);
const threeLevel = twoLevel.getIn([0,'more']);
console.log(firstLevel.toJS(),twoLevel.toJS(),threeLevel.toJS());
As for a more generative solution, I re-wrote the answer before to a recursive approach:
function mapDeep(firstLevel) {
return firstLevel.map((obj) => {
if (obj.has('more')) {
const sec = obj.get('more').toMap().mapKeys((key, value) => value.get('value'));
const objNext = mapDeep(sec);
obj = obj.set('more', objNext);
}
return obj;
});
}
The first level still needs to be mapped manually before.
const firstLevel = data.toMap().mapKeys((key, value) => value.get('value'));
const secondLevel = mapDeep(firstLevel);
Again, see it in action: https://jsfiddle.net/9f0djcb0/12/
This is good enough for me for now. Still feels like this can be solved smarter (and more performant).. Cheers :)
So after some time passed I came up with a solution that works for me:
let sec, third, objThird;
// 1st level: simple mapping
const firstLevel = data.toMap().mapKeys((key, value) => value.get('value'));
// 2nd level: walk through updated firstLevel's subobjects and do the mapping again:
const secondLevel = firstLevel.map((obj) => {
if (obj.has('more')) {
sec = obj.get('more').toMap().mapKeys((key, value) => value.get('value'));
// 3nd level: walk through updated secondLevel's subobjects and do the mapping again:
objThird = sec.map((o) => {
if (o.has('more')) {
third = o.get('more').toMap().mapKeys((key, value) => value.get('value'));
o = o.set('more', third);
}
return o;
});
obj = obj.set('more', objThird);
}
return obj;
});
See it in action here: https://jsfiddle.net/9f0djcb0/7/
This has been working nicely so far, thur pretty hard-coded. If anyone has a more elegant solution to this, I am happy to learn about it!

ExtJS 4 MVC, Get Checkbox value integer instead of bool

I'm using a form to edit Model. I receive data in JSON. Here's my problem:
I receive data for Checkbox only in INT: 1 or 0, I cannot change it. JSON:
{ "checkboxValue": 1 }
This field in ExtJS model is defined as INT type. Model:
{name: "checkboxValue", type: Ext.data.Types.INT},
then I set values to form this way:
formCmp.loadRecord(loadedStore.getAt(0));
and my checkbox is set correctly: when I receive 1 it's checked, 0 - unchecked.
But when I try to save record and send data to server this way:
form.updateRecord(form.getRecord());
record.save();
I need Checkbox to have also INT value - 1 or 0. But it has only BOOL value - true or false so when JSON is sent that value is NaN.
{
"checkboxValue": NaN
}
I think, that function .updateRecord(..) go through all elements and when it gets to checkbox it tries to get value, and the value is BOOL
Does anybody know how to make checkbox' output value INT?
Ext.form.Basic.updateForm uses getFieldValues method to retrieve new data for the updated record, while getFieldValues method returns only boolean values for checkboxes regardless of such properties as inputValue or uncheckedValue. So I would use convert function for the model's field to transform provided boolean value into an integer in a way like that:
Ext.define('MyModel', {
extend: 'Ext.data.Model',
fields: [
{
name: 'flag',
type: 'int',
convert: function (v, record) {
return typeof v === 'boolean' ? (v === true ? 1 : 0) : v;
}
}
],
...
});
Here is a complete jsfiddle
I think it can be done with some simple overrides
Ext.create('Ext.form.Panel', {
bodyPadding: 10,
width: 300,
title: 'Pizza Order',
items: [
{
xtype: 'fieldcontainer',
fieldLabel: 'Toppings',
defaultType: 'checkboxfield',
items: [
{
boxLabel : 'Topping?',
name : 'topping',
id : 'checkbox1',
// include these two properties in your checkbox config
uncheckedValue: 0,
setValue: function(checked) {
var me = this;
arguments[0] = checked ? 1 : me.uncheckedValue;
me.callParent(arguments);
return me;
}
}
]
}
],
renderTo: Ext.getBody()
});

kendoAutoComplete expects that JSON reponse contains the same propertyname as the search filter

Datasource is defined as:
var KendoDataSource_EmployeeAutoCompleteByFirstName = {
serverFiltering: true,
serverPaging: true,
serverSorting: true,
pageSize: 10,
transport: {
read: {
url: '#Url.Action("GetEmployeesByFirstName", "Employee")',
dataType: "json"
}
}
};
AutoComplete is defined as:
function KendoGridFilterAutoComplete(element, kendoDataSource, textField) {
element.kendoAutoComplete({
minLength: 3,
filter: "startswith",
dataSource: kendoDataSource,
dataTextField: textField
});
}
When using a kendoAutoComplete widget, the filter which is send by the datasource is like:
filter[logic]=and&
filter[filters][0][value]=smith&
filter[filters][0][operator]=startswith&
filter[filters][0][field]=LastName&
filter[filters][0][ignoreCase]=true
The JSON response from the server looks like:
[
{"First":"Bill","LastName":"Smith"},
{"First":"Jack","LastName":"Smith"},
{"First":"ABC","LastName":"Smithy"}
]
This works fine, however as you can see I return multiple entries, so the kendoAutoComplete shows two the same entries (Smith) because the first-name differs.
So what I actually want is do distinct on the server, and return only the possible LastName, as an array of strings like this:
[
"Smith",
"Smithy"
]
However the kendoAutoComplete cannot handle this. It shows "undefined" or an error.
How to solve this ?
I've create the following code:
#region AutoComplete
public virtual IQueryable GetAutoComplete(KendoGridRequest request)
{
// Get filter from KendoGridRequest (in case of kendoAutoComplete there is only 1 filter)
var filter = request.FilterObjectWrapper.FilterObjects.First();
// Change the field-name in the filter from ViewModel to Entity
string fieldOriginal = filter.Field1;
filter.Field1 = MapFieldfromViewModeltoEntity(filter.Field1);
// Query the database with the filter
var query = Service.AsQueryable().Where(filter.GetExpression1<TEntity>());
// Apply paging if needed
if (request.PageSize != null)
{
query = query.Take(request.PageSize.Value);
}
// Do a linq dynamic query GroupBy to get only unique results
var groupingQuery = query.GroupBy(string.Format("it.{0}", filter.Field1), string.Format("new (it.{0} as Key)", filter.Field1));
// Make sure to return new objects which are defined as { "FieldName" : "Value" }, { "FieldName" : "Value" } else the kendoAutoComplete will not display search results.
return groupingQuery.Select(string.Format("new (Key as {0})", fieldOriginal));
}
public virtual JsonResult GetAutoCompleteAsJson(KendoGridRequest request)
{
var results = GetAutoComplete(request);
return Json(results, JsonRequestBehavior.AllowGet);
}
#endregion
Which returns a unique list of anonymous objects which look like { "LastName" : "a" }.

Mongoose .populate() only showing 1 document

I am trying to output just the hometeam name's to the page so that I can try to understand how to work with my code better. It is only printing one team to the page, and it is printing all the details of that team to the page, whereas I only want it to print one part.
This is my code, I want it to print the name's of each hometeam to the page
app.get('/home', function(req, res) {
Match.findOne({}).populate('hometeam.name').exec(function(err, teams){
util.log(teams);
res.send(teams);
});
});
But when I load the page all I get is the first piece of data from this list of Matches
[
{
"hometeam": "5106e7ef9afe3a430e000007",
"_id": "5113b7ca71ec596125000005",
"__v": 0,
"key": 1360246730427
},
{
"hometeam": "5113c13e0eea687b28000001",
"_id": "5113e951354fe70330000001",
"__v": 0,
"key": 1360259409361
},
{
"hometeam": "5113c13e0eea687b28000001",
"_id": "5113e999354fe70330000002",
"__v": 0,
"key": 1360259481412
}
]
Also, if I try to put util.log(teams.hometeam.name) I get the following:
TypeError: Cannot call method 'toString' of undefined
But I would want it to be able to print the name which belongs to hometeam here. As hometeam is just the objectId of a Team in my database, am I missing something with the DBreferencing here?
Update:
Team Schema
var Team = new Schema({
'key' : {
unique : true,
type : Number,
default: getId
},
'name' : { type : String,
validate : [validatePresenceOf, 'Team name is required'],
index : { unique : true }
}
});
module.exports.Schema = Team;
module.exports.Model = mongoose.model('Team', Team);
Match Schema
var Team = require('../schemas/Team').Schema;
var Match = new Schema({
'key' : {
unique: true,
type: Number,
default: getId
},
'hometeam' : { type: Schema.ObjectId, ref: 'Team' },
'awayteam' : { type: Schema.ObjectId, ref: 'Team' }
});
module.exports = mongoose.model('Match', Match);
Populate takes the property name of the property you are trying to retrieve. This means that you should use 'hometeam' instead of 'hometeam.name'. However, you want to retrieve the name of the team so you could filter for that. The call would then become..
Match.findOne({}).populate('hometeam', {name: 1}).exec(function(err, teams)
Now you have a property called 'hometeam' with in that the name. Have fun :)
EDIT
Showing how to have a single mongoose instance in more files to have correct registration of schemas.
app.js
var mongoose = require('mongoose');
var Team = require('./schemas/team-schema')(mongoose);
var Match = require('./schemas/match-schema')(mongoose);
// You can only require them like this ONCE, afterwards FETCH them.
var Team = mongoose.model('Team'); // LIKE THIS
schemas/match-schema.js
module.exports = function(mongoose) {
var Match = new mongoose.Schema({
'key' : {
unique: true,
type: Number,
default: getId
},
'hometeam' : { type: mongoose.Schema.ObjectId, ref: 'Team' },
'awayteam' : { type: mongoose.Schema.ObjectId, ref: 'Team' }
});
return mongoose.model('Match', Match);
};
schemas/team-schema.js
module.exports = function(mongoose) {
var Team = new mongoose.Schema({
'key' : {
unique : true,
type : Number,
default: getId
},
'name' : { type : String,
validate : [validatePresenceOf, 'Team name is required'],
index : { unique : true }
}
});
return mongoose.model('Team', Team);
};