How to reference dist/js files from mvc view index.cshtml - asp.net-mvc

I have combined a CLI generated Vue application with ASP.NET Core web application.
I want to create a new entry point and use this new entry point in the MVC view while not impacting the existing main.js entry point.
I am using the following vue.config.js file to add the second entry point.
// https://cli.vuejs.org/config/#pages
module.exports = {
pages: {
index: {
// entry for the page
entry: 'src/main.js',
// the source template
template: 'public/index.html',
// output as dist/index.html
filename: 'index.html',
// when using title option,
// template title tag needs to be <title><%= htmlWebpackPlugin.options.title %></title>
title: 'Index Page',
// chunks to include on this page, by default includes
// extracted common chunks and vendor chunks.
chunks: ['chunk-vendors', 'chunk-common', 'index']
},
index2: {
// entry for the page
entry: 'src/index2.js',
// the source template
template: 'public/index2.html',
// output as dist/index.html
filename: 'index2.html',
// when using title option,
// template title tag needs to be <title><%= htmlWebpackPlugin.options.title %></title>
title: 'Index2 Page',
// chunks to include on this page, by default includes
// extracted common chunks and vendor chunks.
chunks: ['chunk-vendors', 'chunk-common', 'index2']
},
// when using the entry-only string format,
// template is inferred to be `public/subpage.html`
// and falls back to `public/index.html` if not found.
// Output filename is inferred to be `subpage.html`.
//subpage: 'src/subpage/main.js'
}
}
In the Views/Index.cshtml how can I reference the necessary files when the generated files include a hash. i.e. i need to reference index2.24ba2458.js and chunk-vendors.869468b2.js (as well as the css files)
Can I redirect the output directory for index2.html to /Views/Home/Index2.cshtml?
Is it possible that I can serve a HMR js to an mvc view?

You can disable the filename hashing in the config so that you can reference the js file output to the dist directory.
module.exports = {
filenameHashing: false,

Related

vue.js how to pass data to root element

I'm currently building an application using a dotnet core backend and some Vue.js elements in the front. I was able to build the application using regular Vue (non template, plain non es6 javascript syntax) in a cshtml file, but I've been trying to move towards a more modular structure using vue components in .vue files.
The problem I'm running into is that in the original version, I would have access to Json objects when instantiating the root element:
var jsonRenderedWithHtml = #Html.Raw(Json.Serialize(Model.SomeJsonObject));
vm = new Vue({
el: "#root-element",
data: {
vueData: jsonRenderedFromHtml;
}, ...
When I switch over to the component version, from what I've found, I need to render the root element from a javascript file, doing something like this:
import RootElement from "../Vue/RootElement.vue";
import Vue from 'vue';
let vm = new Vue({
el: '#root-element',
render: h => h(RootElement)
});
Then, I would import this script in the #section Scripts part of the cshtml file. Unfortunately, from within the javascript file, there doesn't seem to be a way to pass in data from outside (from the cshtml file). It seems that if I were to instead write an AJAX request inside the vue root instance, it would need to do two server requests to do the same job.
It also seems that I can't use import statements within cshtml (don't seem to be any webpack loaders for cshtml?). Otherwise, I would skip rendering the element in a separate javascript file.
What we did in our application was to output the data added to the ViewData into the view through as json into a script tag and added an object to the window in the script with the previously rendered json. In the beforeCreate we then read the data from the object we added to the window and commit it to our store. Something like:
#{
IHtmlString myObj = null;
if(ViewData["SomeObject"] is ContentResult)
myObj = Html.Raw(((ContentResult)ViewData["SomeObject"]).Content);
<script type="text/javascript">
(function(){
window.obj = JSON.parse(myObj);
});
</script>
You could however add a prop to your App and pass the object in through the prop just create your vue instance in a script tag.

Yeoman: how to avoid file overwrite conflict message when modifying file created by subgenerator?

Overview
I am creating a yeoman generator that will generate a customized angular app. It will be generating custom angular controllers and services.
While I could simply take a current angular template, as generated by the angular generator, add my code, and then save this as a template in my generator, I prefer to have the generator call the "official" angular generator (previously installed by the user) as a subgenerator at runtime, so I don't have to synchronize my templates every time the angular generator template changes.
Problem
I have this working, but the only problem is when, from my generator, I add my code to the file generated by the subgenerator (e.g a controller), I get the message:
conflict app/scripts/controllers/mycontroller.js
? Overwrite app/scripts/controllers/mycontroller.js? overwrite
force app/scripts/controllers/mycontroller.js
Is there a way I can get the file generated by the subgenerator before it's written to disk, so I can edit it, without generating the overwrite prompt?
I think it's confusing to be prompted about overwriting a file that is being created for the first time.
Data
In reading the yeoman doc, it makes it sound like generators and subgenerators share the same "soft" in-memory filesystem:
"As asynchronous APIs are harder to use, Yeoman provide a synchronous file-system API where every file gets written to an in-memory file system and are only written to disk once when Yeoman is done running. This memory file system is shared between all composed generators."
But it appears that the subgenerator writes the files to disk and not the in-memory file system. Unfortunately, I do not have control over the subgenerator, as it's the standard angular yeoman generator.
Here is my generator (scroll down to portion marked "Relevant Portion"):
'use strict';
var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var yosay = require('yosay');
module.exports = yeoman.generators.Base.extend({
prompting: function () {
var done = this.async();
// Have Yeoman greet the user.
this.log(yosay(
'Welcome to the epic ' + chalk.red('AngularVr') + ' generator!'
));
var prompts = [{
type: 'confirm',
name: 'someOption',
message: 'Would you like to enable this option?',
default: true
}];
this.prompt(prompts, function (props) {
this.props = props;
done();
}.bind(this));
},
writing: {
app: function () {
this.fs.copy(
this.templatePath('_vt_marker.json'),
this.destinationPath('vt_marker.json')
);
},
====================== Relevant Portion ===============
subgenerators: function () {
this.log("now executing subgenerators");
this.composeWith('angular:controller', {args: ['mycontroller']} );
this.log("now done with subgeneration");
},
subgenerators_read: function () {
// add a new line to generated file..this generates overwrite prompt
var fp = this.destinationPath('app/scripts/controllers/mycontroller.js');
var fc = this.fs.read(fp);
fc += '\nhello there\n';
this.fs.write(fp, fc);
},
});
This is my first attempt at writing a yeoman generator.
Many Thanks.
The issue is probably just that either your generator or the generator-angular is running on an old version of yeoman-generator.
Latest version at this time is 0.20.3 https://www.npmjs.com/package/yeoman-generator

Angular-gettext extract annotations from .cshtml file

I'm using Angular-gettext to extract strings from .html and .js files for multi-language translation using Gruntfile.js:
grunt.initConfig({
nggettext_extract: {
pot: {
files: {
'po/template.pot': ['**/*.html', '**/*.cshtml', '**/controller.caseload.js']
}
},
}
But when I try to pull from a .cshtml file, it is not being extracted.
I need to extract from my Header.cshtml file because I am using it as my Layout for my angular app. The layout basically displays a header bar at the top of every page that contains user information (Profile, Preferences, Logout, etc.).
When I try to add a line like <div translate>Preferences<div> to my Header.cshtml file, it doesn't extract into my .pot file. But if I add that same line to my index.html file, it extracts correctly and I am then able to define a translation for it.
Is there a good way to do this with angular-gettext for .cshtml files?
Try to add this code to your option section.
options: {
extensions: {
htm: 'html',
html: 'html',
php: 'html',
phtml: 'html',
tml: 'html',
js: 'js',
cshtml: 'html'
}
Maybe it's trying to parse your template as a Javascript by default.

How to I preload existing files and display them in the blueimp upload table?

I am using the jquery-ui version of Blueimp upload and I like how I can format a table and display files that were just uploaded. But I'd like to use it as a file manager as well so I want to preload existing files and display than as if they were just uploaded. How can I do that? A sample link to where someone else has addressed this would suffice. BTW, I am uploading several different file types, not just images.
Thanks!
Or without an ajax call:
Prepare array containing details of existing files, e.g:
var files = [
{
"name":"fileName.jpg",
"size":775702,
"type":"image/jpeg",
"url":"http://mydomain.com/files/fileName.jpg",
"deleteUrl":"http://mydomain.com/files/fileName.jpg",
"deleteType":"DELETE"
},
{
"name":"file2.jpg",
"size":68222,
"type":"image/jpeg",
"url":"http://mydomain.com/files/file2.jpg",
"deleteUrl":"http://mydomain.com/files/file2.jpg",
"deleteType":"DELETE"
}
];
Call done callback
var $form = $('#fileupload');
// Init fileuploader if not initialized
// $form.fileupload();
$form.fileupload('option', 'done').call($form, $.Event('done'), {result: {files: files}});
I also had the same problem. It is not magic how it works. I recommend to examine the UploadHandler.php file. Then you will be able to modify this plugin accordind to your needs.
The code above in your second post is just an ajax call to the uploader script (by default index.php in server/php/ folder). The call method is set to "get" by default in $.ajax object.
Open the UploadHandler.php file and go to the class method "initialize(...)". You will see how the call with "get" handled. UploadHandler calls the class method this->get(.:.) to prepare and send the list of existing files. If you use other upload directory, you need pass a parameter to the UploadHänder. Simply chage the url property in the $.ajax object like :
url: $('#fileupload').fileupload('option', 'url')+'?otherDir='+myDir,
then you should initialize the option property of the UploadHandler before you create a new UploadHandler object like this:
$otherDir = trim($_REQUEST['otherDir']);
$otherDir_url = [anyURL] .'/'.$otherDir;//so that the files can be downloaded by clicking on the link
$options = array(
'upload_dir'=> $otherDir,
'upload_url'=> $otherDir_url,
);
$upload_handler = new UploadHandler($options);
Found the code in the main js file... It wasn't obvious how it worked. Got it working just fine.
// Load existing files:
$.ajax({
url: $('#fileupload').fileupload('option', 'url'),
dataType: 'json',
context: $('#fileupload')[0]
}).done(function (result) {
$(this).fileupload('option', 'done').call(this, null, {result: result});
});
If any of you looking at this is doing it in .NET, find this: (for me it is in application.js
For a fairly recent version, there is a function
// Load existing files:
$.getJSON($('#fileupload form').prop('action'), function(files) {
files = somethingelse;
var fu = $('#fileupload').data('fileupload');
fu._adjustMaxNumberOfFiles(-files.length);
fu._renderDownload(files)
.appendTo($('#fileupload .files'))
.fadeIn(function() {
// Fix for IE7 and lower:
$(this).show();
});
});
Inside the application.js
I'm doing it for .NET though, and actually needed this gone.
Then set your somethingelse to either your files or "" depending on what you want to show. If you remove the line files = somethingelse then it will preload all files from the folder.

Way to organize client-side templates into individual files?

I'm using Handlebars.js, and currently all my templates live inside script tags which live inside .html files housing dozens of other templates, also inside script tags.
<script type="text/template" id="template-1">
<div>{{variable}}</div>
</script>
<script type="text/template" id="template-2">
<div>{{variable}}</div>
</script>
<script type="text/template" id="template-3">
<div>{{variable}}</div>
</script>
...
Then I include this file on the server-side as a partial.
This has the following disadvantages:
A bunch of templates are crammed into HTML files.
Finding a given template is tedious.
I'm looking for a better way to organize my templates. I'd like each each template to live in its own file. For example:
/public/views/my_controller/my_action/some_template.html
/public/views/my_controller/my_action/some_other_template.html
/public/views/my_controller/my_other_action/another_template.html
/public/views/my_controller/my_other_action/yet_another_template.html
/public/views/shared/my_shared_template.html
Then at the top of my view, in the backend code, I can include these templates when the page loads, like this:
SomeTemplateLibrary.require(
"/public/views/my_controller/my_action/*",
"/public/views/shared/my_shared_template.html"
)
This would include all templates in /public/views/my_controller/my_action/ and also include /public/views/shared/my_shared_template.html.
My question: Are there any libraries out there that provide this or similar functionality? Or, does anyone have any alternative organizational suggestions?
RequireJS is really good library for AMD style dependency management. You can actually use the 'text' plugin of requireJS to load the template file in to your UI component. Once the template is attached to the DOM, you may use any MVVM, MVC library for bindings OR just use jQuery events for your logic.
I'm the author of BoilerplateJS. BoilerplateJS reference architecture uses requireJS for dependency management. It also provides a reference implementations to show how a self contained UI Components should be created. Self contained in the sense to handle its own view template, code behind, css, localization files, etc.
There is some more information available on the boilerplateJS homepage, under "UI components".
http://boilerplatejs.org/
I ended up using RequireJS, which pretty much let me do this. See http://aaronhardy.com/javascript/javascript-architecture-requirejs-dependency-management/.
I use a template loader that loads the template using ajax the first time it is needed, and caches it locally for future requests. I also use a debug variable to make sure the template is not cached when I am in development:
var template_loader = {
templates_cache : {},
load_template : function load_template (params, callback) {
var template;
if (this.templates_cache[params.url]){
callback(this.templates_cache[params.url]);
}
else{
if (debug){
params.url = params.url + '?t=' + new Date().getTime(), //add timestamp for dev (avoid caching)
console.log('avoid caching url in template loader...');
}
$.ajax({
url: params.url,
success: function(data) {
template = Handlebars.compile(data);
if (params.cache){
this.templates_cache[params.url] = template;
}
callback(template);
}
});
}
}
};
The template is loaded like this:
template_loader.load_template({url: '/templates/mytemplate.handlebars'}, function (template){
var template_data = {}; //get your data
$('#holder').html(template(template_data)); //render
})
there's this handy little jquery plugin I wrote for exactly this purpose.
https://github.com/cultofmetatron/handlebar-helper

Resources