how to get stored options from `this.prompt` inside yeoman context? - javascript

Basically, yeoman force you to ask everything you need from developer. Although, it’s a good thing, that you can store something and in future runs these things will be autocompleted for developer. The point is that I want to not ask developer if he already answered on that questions.
here is example of basic yeoman generator (name will be saved and autocompleted later):
var yeoman = require('yeoman-generator');
module.exports = yeoman.generators.Base.extend({
init: function () {
var cb = this.async();
this.prompt([{
name: 'name',
message: 'your name:',
store: true,
}, {
name: 'moduleName',
message: 'module name:'
}], function (props) {
console.log(
props.name, // developer’s name
props.moduleName // module’s name
)
}.bind(this));
},
}
});
The question is how to get stored options from this.prompt inside yeoman context to do smth like this:
this.prompt([!this.name.stored && {
name: 'name', // so after first run this will never be asked again
message: 'your name:',
store: true,
}, {
name: 'moduleName',
message: 'module name:'
}], function (props) {
console.log(
props.name, // developer’s name
props.moduleName // module’s name
)
}.bind(this));

There's no public way to access the stored previous prompt answers.
If you want to cache some data and access it later, then use the storage functionality (this.config)
FWIW, the prompt cache is stored into the private this._globalConfig. I'm adding this detail for completeness, you probably shouldn't use it.

You can user default's value as function, where first argument is prev stored answers:
const answers = await this.prompt([
{
type: 'input',
name: 'projectName',
message: 'Your project id',
default: this.appname,
store: true
},
{
type: 'input',
name: 'projectTitle',
message: 'Your project title',
default: ({ projectName }) => projectName
},
])

You can add a config.js that will store and read the information in the users home directory as a config.json file and later the app can read this file that can be used as a default.
{
name: 'authorName',
message: 'What\'s your name?',
'default': self.defaultAuthorName
}
Check out https://www.npmjs.com/package/generator-yo-wordpress where the developer makes use of a config.js file.

Related

Web Scraping with Javascript?

I'm having a hard time figuring out how to scrape this webpage to get this wedding list into my onepager. It doesn't seem complicated at first but when I get into the code, I just can't get any results.
I've tried ygrab.js, which was fairly simple and got me somewhere but then I can't seem to scrape the images and it only prints the output in the console (not much documentation to go on).
$(function() {
var $listResult = $('#list-result');
var kado = [];
var data = [
{
url: 'https://www.kadolog.com/fr/list/liste-de-mariage-laura-julien',
selector: '.kado-not-full',
loop: true,
result: [{
name: 'photo',
find: '.views-field-field-photo',
grab: {
by: 'attr',
value: 'src'
}
},
{
name: 'title',
find: '.views-field-title .field-content',
grab: {
by: 'text',
value: ''
}
},
{
name: 'description',
find: '.views-field-body .field-content',
grab: {
by: 'text',
value: ''
}
},
{
name: 'price',
find: '.price',
grab: {
by: 'text',
value: ''
}
},
{
name: 'remaining',
find: '.topinfo',
grab: {
by: 'text',
value: ''
}
},
{
name: 'link',
find: '.views-field-nothing .field-content .btn',
grab: {
by: 'attr',
value: 'href'
}
},
],
},
];
ygrab(data, function(result){
console.log(JSON.stringify(result, null, 2)); //photos = undefined
});
Then there's Node.js with Request and Cheerio (and I tried Crawler too), but I have no idea how node works.
var request = require("request");
This gives me an error in the console saying require is not defined. Fair enough, I added require.js to the scripts in my page. I got another error ("Uncaught Error: Mismatched anonymous define() module: ...").
My question is this: Is there a simple Javascript way (possibly without involving node?), to scrape the wedding list I'm trying to get? Or maybe a tutorial that resembles what I'm trying to do step by step ?
I'd be truly grateful for any help or advice.
i think your only issue is the img selector.
Change
{
name: 'photo',
find: '.views-field-field-photo',
grab: {
by: 'attr',
value: 'src'
}
},
To this
{
name: 'photo',
find: '.views-field-field-photo .field-content img',
grab: {
by: 'attr',
value: 'src'
}
},
I actually can't test this right now, but it should be working!!
Node.js is a seperate application that executes javascript independent of a web page.
require is Node's way of importing packages, and isn't defined by the browser, require.js is a javascript library for requiring packages, but it doesn't work the same way as Node's require function.
To use request and cheerio, you'd need to install Node.js from here, then install request and cheerio with the following commands:
npm install request --save
npm install cheerio --save
Then any code you write with Node.js in that directory will have access to the modules.
Here's a tutorial to web scraping in Node.js with cheerio.

Mongoose find not working on default attribute

This is probably really simple, but I can't see what I'm missing.
Here is my model:
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var JobSchema = new Schema({
type: String,
scheduled: { type:Boolean, default:false },
state: { type: String, default: 'initial' },
details: {},
changes: [],
lastModified: { type: Date, default: Date.now },
});
//RECCOMMENDED TO TURN OFF IN PRODUCTION?
JobSchema.index({type:1, state:1, "details.prodId":1});
module.exports = mongoose.model('Job', JobSchema);
However, whenever I run the following code nothing is returned:
Job.find({state:'initial'},function(err,data){
console.log(data.length);
});
I've tested this same code on other attributes, works.
Also here is some example db data:
[
{
"_id":"55709ed07df3b4b1f034311a",
"details": {
"quantity":"10",
"price":"45.28",
"prodId":"321product",
"storeId":"338store"
},
"lastModified":"2015-06-06T18:00:28.348Z",
"changes":[],
"state":"initial",
"scheduled":true
},...
UPDATE
Ok I changed some values of state from 'initial' to 'pending' and mongo finds the 'pending', however, it doesn't recognize 'initial', and returns 0 results.
Probably your querying to a database that is not supposed to be used.
I have run the same code on my computer and actually it finds a job with initial state, I have created a gist with the code that I run in my computer in a file called app.js : https://gist.github.com/wilsonbalderrama/653c34acf19871115f64
You need to have your mongodb server up and running and then please install the dependencies that are:
$ npm install mongoose async
then run the file:
$ node app.js
Let me know if it works this code for you.

How to add another field in a join sails js

Hey all just getting started with Sails js and mongoDB and im a bit confused.
I have two models with a many-to-many relationship:
User.js
module.exports = {
attributes: {
username: 'STRING',
password: 'STRING',
doors:{
collection: 'door',
via: 'users',
}
}
};
and Door.js
module.exports = {
attributes: {
name: 'STRING',
users:{
collection: 'user',
via: 'doors'
}
}
};
This works fine, I can create a user and a door and associate one with the other. However I'd like to have another field in the join, an expiry date (Say the user can only have access to a particular door until a particular date).
How would I go about doing that?
You need to create a many to many through association. However they are not officially supported as of yet.
You can manually do this however.
Now, in this example it may sometimes be a a little more difficult to get all the doors for a user and vice versa, because you have to preform a second look up. However you can do the following with this setup:
UserDoors
.find()
.where({expires:{'<':new Date()}})
.populate('doors')
.populate('users')
.exec(/*....*/)
Your models
User.js
module.exports = {
attributes: {
username: 'STRING',
password: 'STRING',
doors:{
collection: 'userDoors',
via: 'users',
}
}
};
userDoors.js
module.exports = {
attributes: {
doors:{
model: 'door'
},
users:{
model: 'user'
},
expires: 'datetime'
}
};
and Door.js
module.exports = {
attributes: {
name: 'STRING',
users:{
collection: 'userDoors',
via: 'doors'
}
}
};
Do a google search for sails.js many to many through to also help you find what your looking for.

Make ember to resolve hasMany relationship when loading

I'm currently facing a big problems for days. I'm using ember simple-auth plugin which provide me a session object accessible through the code or the templates. That session object store the account information such as username, id and rights.
My models are like this :
App.Right = DS.Model.extend({
label: DS.attr('string', { defaultValue: undefined })
});
App.Right.FIXTURES = [
{
id: 1,
label: 'Admin'
}, {
id: 2,
label: 'Manager'
}, {
id: 3,
label: 'User'
}
];
App.User = DS.Model.extend({
username: DS.attr('string'),
rights: DS.hasMany('right', {async: true})
});
App.User.FIXTURES = [
{
id: 1,
username: "Someone",
rights: [1]
}
];
Then I have (as specified on the simple-auth documentation) this setup :
App.initializer({
name: 'authentication',
initialize: function(container, application) {
Ember.SimpleAuth.Session.reopen({
account: function() {
var userId = this.get('userId');
if (!Ember.isEmpty(userId)) {
return container.lookup('store:main').find('user', userId);
}
}.property('userId')
});
...
}
});
Inside one of my view I'm doing this:
this.get('context.session.account.rights').toArray()
but it gives me an empty array. That piece of code is executed inside an Ember.computed property.
The question is how can I resolve the childrens of account before rendering the view ?
Since async: true this.get('context.session.account.rights') will return a promise object so you will have to use this.get('context.session.account.rights').then(... see: http://emberjs.com/api/classes/Ember.RSVP.Promise.html#method_then
Okay so I finally got it to work. It doesn't solve the original question because the original question was completely stupid. It's just IMPOSSIBLE to resolve relationships synchronously when you use the async: true. Trying to resolve it in advance is NOT the solution because you will still not know when it has actually resolved.
So here is the solution:
$.each(this.get('cellContent.buttonList'), function(i, button) {
button.set('hasAccess', false);
this.get('context.session.account').then(function(res) {
res.get('rights').then(function(result) {
button.set('hasAccess', Utils.hasAccess(result.toArray(), button.rights));
});
});
});
Using the following cellContent.buttonList definition:
buttonList: [
Ember.Object.create({
route: 'order',
label: 'Consult',
rights: 'all'
}), Ember.Object.create({
route: 'order.edit',
label: 'Edit',
rights: [1, 2]
})
]
Explanation
We have to use Ember.Object in order to have access to the set method. Using an Ember object is very handy. It allows us to change the value of properties after the render process making the view to update according to the new value you just set.
Because it updates the view, you don't have to care anymore whether your model has resolved or not.
I hope this will help people as much as it helps me.

How execute other prompt when prompt previous is true on Yeoman?

How execute prompt2 when prompt1 is true on Yeoman as shown below?
var prompts = [
{name: 'prompt1', message: 'Ask 1?'},
{name: 'prompt2', message: 'Ask 2?'}
];
Yeoman uses a thing called Inquirer.js for the prompt system. Here's an example of how you can ask Question 2 if Question 1 was true:
inquirer.prompt([{
name: 'movie',
type: 'confirm',
message: 'Have you seen a movie lately?'
}, {
when: function (response) {
return response.movie;
},
name: 'good-or-not',
message: 'Sweet! Was it any good?'
}], function (response) {});
From the Inquirer.js documentation:
when: (Function) Receive the current user answers hash and should return true or false depending on wheter or not this question should be asked.

Categories

Resources