I am running a simple gulp task that is supposed to render my handlebars template version in a specific language. The language data is stored in a JSON file and i require that dynamically inside a gulp pipe task I store that in a variable and then the handlebars task executes.
gulp.task('compilen', () => {
var strings;
return gulp.src('frontend/templates/*/*.hbs')
.pipe(through.obj(function(file,enc,cb){
var p = parsePath(file.relative);
strings = require('./frontend/templates/' + p.dirname+ '/locales/en.json');
console.log(strings);
cb(null,file);
}))
.pipe(handlebars(strings, options))
.pipe(rename(function(path){
path.basename += "-en";
path.extname = ".html";
}))
.pipe(gulp.dest('build'));
});
Whenever I run gulp everything runs and it outputs a file without the strings data. The {{ }} are removed but there is no actual data as if the strings object were empty but that is not the case since whenever I wrap the handlebars function with tap and console.log the values they all there.. What is even more strange is that instead of the strings variable if I were to pass an object literal, everything renders correctly.
here is a sample hbs template and my json file
main.hbs
{{> header}}
<div>
{{home.title}}
</div>
en.json
{
"home" : {
"title" : "hello world",
"heading" : "1245"
}
}
the main.html output
<div>
</div>
<div>
</div>
I solved this by using yet another plugin gulp-data reference in the bottom of the docs. I replaced through.obj with the gulp-data object and it works now. I've been struggling to much trying to do simple things with gulp so my advice is to stay away.
Related
I have some JSON files in my Webpack application that I want to import. They have names such as 0.json, 1.json, 2.json, and so on and are inside of the directory src/res/level/. When I try to require() them in my code, it does not work:
private loadWorld() {
// load the level
// duplicate the object to avoid modifying the actual instance
// that json-loader created
this.state.level = JSON.parse(JSON.stringify(require(`#res/level/${this.level}.json`))) as LevelData;
// ...
}
This line in my method always throws an error:
Error: Cannot find module "#res/level/1.json".
at webpackContextResolve (webpack-internal:///9:16:11)
at webpackContext (webpack-internal:///9:9:11)
However, I cannot figure out why. And to make things more confusing, if I run Webpack in watch mode, and I edit this line before my program tries to run it, then the JSON files are suddenly loaded properly.
I have configured my alias for #res properly:
resolve: {
extensions: [".ts", ".js", ".glsl", ".json"],
alias: {
"#res": path.join(__dirname, "src/res"),
"#lib": path.join(__dirname, "src/lib"),
"#shader": path.join(__dirname, "src/shader"),
"#control": path.join(__dirname, "src/control"),
"#scene": path.join(__dirname, "src/scene"),
"#util": path.join(__dirname, "src/util"),
}
}
And because this is Webpack 4, I simply did not include a loader for JSON.
So why is this not working?
Additionally, I notice that when I inspect the generated code, I see this:
Which suggests that the JSON files are being loaded, but not under the directory that I expect.
The compiler began to load the JSON files consistently when I used string concatenation instead of a template string:
this.state.level = JSON.parse(JSON.stringify(require("#res/level/" + this.level.toString() + ".json"))) as LevelData;
I'm using Angular 4 to develop an app which is mainly about displaying data from DB and CRUD.
Long story short I found that in Angular 4 the component html doesn't like displaying loosely typed object (leaving the space blank while displaying other things like normal with no warning or error given in console) even if it can be easily displayed in console.log output, as shown in a string.
So I made a function in the service file to cast the values into a set structure indicating they're strings.
So now something like this works:
HTML
...
<div>{{something.value}}</div>
...
Component.ts
...
ngOnInit() {
this.route.params.subscribe(params => {
this.pkey = params['pkey'];
this.service.getSomethingById(this.pkey)
.then(
something => {
this.something = this.service.convertToStructure(something);
},
error => this.errorMessage = <any>error);
});
}
...
Code of the function convertToStructure(something)
convertToStructure(someArr: myStructure): myStructure {
let something: myStructure = new myStructure();
something.value = someArr[0].value;
return something;
}
But as I dig into other files for copy and paste and learn skills from what my partner worked (we're both new to Angular) I found that he did NOT cast the said values into a fixed structure.
He thought my problem on not being able to display the values (before I solved the problem) was because of me not realizing it was not a plain JSON object {...} but an array with a single element containing the object [{...}] .
He only solved half of my problem, cause adding [0] in html/component.ts was not able to make it work.
Component.ts when it did NOT work
...
ngOnInit() {
this.route.params.subscribe(params => {
this.pkey = params['pkey'];
this.service.getSomethingById(this.pkey)
.then(
something => {
console.log(something[0].value); //"the value"
this.something = something[0]; //html can't find its value
},
error => this.errorMessage = <any>error);
});
}
...
HTML when it did NOT work
...
<div>{{something[0].value}}</div> <!--Gives error on the debug console saying can't find 'value' of undefined-->
...
And of course when I'm using the failed HTML I only used this.something = something instead of putting in the [0], and vice versa.
So I looked into his code in some other page that display similar data, and I found that he used *ngFor in html to extract the data and what surprised me is that his html WORKED even if both of our original data from the promise is identical (using the same service to get the same object from sever).
Here's what he did in html:
...
<div *ngFor="let obj of objArr" ... >
{{obj.value}}
</div>
...
His html worked.
I'm not sure what happened, both of us are using a raw response from the same service promise but using for loop in html makes it automatically treat the value as strings while me trying to simply inject the value fails even if console.log shows a double quoted string.
What's the difference between having the for loop and not having any for loop but injecting the variable into html directly?
Why didn't he have to tell Angular to use the set structure indicating the values are strings while me having to do all the trouble to let html knows it's but a string?
The difference here is as you said that your JSON is not simple object , its JSON Array and to display data from JSON array you need loop. So, that is why your friends code worked and yours did not. And please also add JSON as well.
Practical example is this best here, so here goes. I have a JSON file named file.json as such:
{
"key": "hello"
}
And a JS file in the same directory as such (NodeJS):
'use strict';
// Dependencies
const jsonFile = require('./file.json');
// Globals
const anotherFile = {
key: 'world'
}
const fn = () => {
console.log(jsonFile.key); // this 'key' is not recognized
console.log(anotherFile.key); // this 'key' is recognized
};
Now, that fn function should, and does, print hello and world to the console. My problem is that while WebStorm recognizes the second file (anotherFile) as a JavaScript object, it doesn't do so with the one imported from the JSON.
That means that anotherFile.key has "key" in purple (in my template) color, while the other one is plain white with the underline that you get when it's "Unresolved variable key".
Also means that I can write anotherFile and it will show me all available options (functions, properties, etc) and key will be there, while in the first file, jsonFile, it wont.
Is there any way to force WebStorm to recognize JSON's as JavaScript objects?
Thanks!
Edit: Using WebStorm 11.0.1
Please try upgrading - your code works fine for me in 2016.2:
In Preference>Editor>File Types you should have this :
But I thought it was like this by default ...
Is possible to feed JSON data to SCSS ?
Currently I'm using jade as a template engine and I use data from a json file, achieving that using gulp-data.
My gulp task is the following:
gulp.task('partials', function () {
"use strict";
return gulp.src(['dev/templates/*.jade', '!dev/templates/partials/**/*.jade'])
.pipe(data(function (file) {
return JSON.parse(
fs.readFileSync('./dev/data/globals.json')
);
}))
.pipe(jade({
pretty: true
}))
.pipe(gulp.dest('dev/'))
// Notify browserSync
// to refresh
.pipe(browserSync.reload({
stream: true
}));
});
And using the data from the json file like this: #{example.test.name}
Is possible to use the same thing in SCSS ?
There's no way to directly handle JSON with SCSS alone. Since you're already using Gulp, you can use an third-party tool such as eyeglass or sassport to convert JSON into a SCSS hash. Another tool available is json-sass, which you can use standalone.
If you're not using Gulp, then you would have to rely on Gem based converters but they don't seem to be actively maintained:
https://github.com/vigetlabs/sass-json-vars
https://github.com/HugoGiraudel/SassyJSON
There are at least two other solutions:
converting JSON to SASS/SCSS variables: https://github.com/rlapoele/json-to-scss
importing JSON into SASS/SCSS: https://github.com/Updater/node-sass-json-importer
I have a controller that uploads and processes a file. Afterwards, I wish to render the processing result in a modal div. I wanted to know what the best way is to get the results from the controller to the modal div on the gsp. I thought about a template but I didn't know how to specify what the target div for the template should be because this template wouldn't be rendered by a button click where a target for template render is set as an attribute, it would be done on a timed basis (i.e. when the file is done uploading). The other way is to send JSON back from the controller but I don't know how to intercept this JSON at the right time because I still don't quite understand the timings of the information flow between the GSP and the Controller. I know how to send the JSON but how to alert the GSP that "hey, some JSON is now ready for your modal that's about to go up." Here is some pseoducode of basically what I am trying to get done.
Controller:
upload() {
// process file and store results in three integers
// int1 = result1
// int2 = result2
// int3 = result3
// send the three numbers to the gsp
}
Now what is the best way to get these three numbers to the GSP so that they are displayed on a modal dialog which is about to go up like this:
<div id="fileUploadResultsModal">
Results:
${int1}, ${int2}, ${int3}
</div>
Here is the JS associated with my ajax upload function:
$("#chseFile").upload("${createLink(controller: 'customer', action: 'upload',)}",
{dataTypegrp: parseInt(getCheckedValue(document.getElementsByName('dataTypegrp'))),
fileTypegrp: parseInt(getCheckedValue(document.getElementsByName('fileTypegrp')))},
function(success) {
$("#cancel1").trigger("click");
setTimeout(function(){
$("#summary").trigger("click");
}, 250);
displaySuccess(data);
},
function(prog, value) {
console.log(value);
$("#prog").val(value);
if (value == 100) {
$("#prog").hide();
$("#progressbar").html("Uploading and processing. Please wait...");
}
});
but right now JS complains that 'data' is not defined. 'data' is meant to be the JSON coming back from the controller.
Thanks
you can render them as JSON:
render( [ int1:111, int2:222, int3:333 ] as JSON )
or as a HTML-string
render "<div id=\"fileUploadResultsModal\">Results:${int1}, ${int2}, ${int3}</div>"
or use a template
render template:'/yourController/templateName', model:[ int1:111, int2:222, int3:333 ]
or a TagLib
render g.yourResultTag( int1:111, int2:222, int3:333 )
For this tiny bit of information, the performance is not of concern. It's rather a matter of taste, or what is more appropriate for your client.
If the later is JSON-biased, use JSON-rendering. If it has a mix of JSON and HTML, use others.
inside controller at the enf of controller action you can use
render [data:['name':'firstname','surname':'secondName'] as JSON]
this will render the data to GSP