Using VueJS in a ASP project - asp.net-mvc

Currently developing a ASP MVC site.
Some sections of the site will use VueJS for displaying some list, forms etc.
The project setup is Bower, Grunt, standard C# ASP project using TypeScript.
This is my first time using Vue, and the simple stuff is pretty stragt forward. Seting up a page with a form, getting data from a WebService etc.
My problem/question is, what, and how, do i get the best setup, for using Single File Components (Vue) in my cshtml view files.
So, lets say I have a section on my site, where i want to display orders from the user.
Layout, navigation etc is setup by my excisting ASP code. I have a CSHTML viewpage for the current page, pretty vanilla:
#inherits MyViewPage<MyViewModel>
#{
Layout = "~/Views/layout.cshtml";
}
<div id"app">
</div>
Thats it for the excisting view page. In this page, i want to include a Vue Single File Component.
Previously i had the markup directly in the CSHTML page, which works fine. But when i want to user Vue-router, it becomes a problem to maintain the different views. So i should move the markup into a Component.
This is the basic setup;
const page1 = { template: '<div>Page1</div>' }
const page2 = { template: '<div>Page2</div>' }
const routes = [
{ path: '/', component: page1 },
{ path: '/page2', component: page2 }
]
const router = new VueRouter({
routes
})
var vm = new Vue({
router,
el: "#app"
})
Lets say i create a .vue file called page1.vue instead. This contains
<template>
my new page
</template>
<script>
export default {
name: '?',
date: function() {
}
}
</script>
How do i get this file included in my CSHTML file for instance?

You need to develop with webpack to build Single File Components.
See the Vue documentation on this.
Use the Vue Cli and drop a web pack build into your cshtml page.

Related

Binding from mvc model to angular2 component (Components in mvc project)

I could use some help, figure out how to pass model data from mvc application to a angular2 component running inside mvc.
Lets say I have a cs.html file that has an component
<my-app></my-app>
This will load the angular2 component. I need to generate some binding to keep mvc models intact with my angular2 models.
First of all, I'm trying to pass a model to the component via the Input property.
CSHTML file:
In the top of my cshtml file, I have:
#model MainModel
<script>
var model = #Html.Json(Model.Form.PassengerModel);
</script>
I want to pass this model to my angular2 component.
What I have tried are:
<my-app passengerModel="model"></my-app>
Angular2 component:
import { Component, Input } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './Content/Scripts/angular2components/app.component.html',
})
export class AppComponent {
#Input() passengerModel: PassengerModel;
constructor() {
console.log("Model loaded?: " + this.passengerModel);
}
}
export class PassengerModel {
constructor(
public Adults: number,
public Children: number
) { }
}
The problem is that the model is undefined always. Is there any way to pass a model in to the component?
The problem you have outlined above is that your binding is not correct for the context you are attempting to use it in.
<my-app passengerModel="model"></my-app>
The above line is telling Angular to bind passengerModel inside your my-app component to a property on the host component named model. This means the page (component) which hosts your my-app component should be a component with a property named model. You have created a global variable which is not in the scope of your host component. Angular2 specifically isolates the scope of each component so that you do not accidentally introduce unwanted side effects.
Save yourself some pain an anguish and embrace Angular fully. Ditching your MVC Page Controllers and moving to WebApi service calls will yield better results and save you the need to translate the model manually among other issues you will run into going down the mixed route.
Considerations:
#Html.Json will ultimately cause your data to be exposed directly in your script tag. This could be a security risk if the data is sensitive and if you start using MVC Model bindings in the page alongside Angular bindings they will fight each other.
Basically these approaches are diametrically opposed as ASP.NET MVC is a server side approach and Angular is a client side approach. Mixing them in the same application will always be awkward at best.
WebApi gives you the JSON serialization more or less for free. Your MVC model is automatically serialized to JSON by the framework when returning an HttpAction. If you are trying to avoid converting your ASP.NET MVC views to Angular Components then I understand. You may not have a choice but if you do I would steer clear of mixing these two.
[HttpGet]
[AcceptVerbs["GET"]
[Route("passengers/{id:int}")]
public IHttpActionResult GetPassenger(int id)
{
// For illistration...
try
{
var passengerModel = PassengerService.LoadPassenger(id);
return Ok(passenger);
}
catch(Exception e)
{
return InternalServerError(e);
}
}
https://angular.io/docs/ts/latest/tutorial/toh-pt6.html
// I would normally put this in the environemnt class..
private passengerUrl = 'api/passengers'; // URL to web api
constructor(private http: Http) { }
getPassenger(id: number): Promise<Passenger> {
return this.http.get(`this.passengerUrl/${id}`)
.toPromise()
.then(response => response.json() as Passenger)
.catch(this.handleError);
}
private handleError(error: any): Promise<any> {
console.error('An error occurred', error); // for demo purposes only
return Promise.reject(error.message || error);
}

Directive for loading forms into a single page app lost controller binding

I'm creating a single page app using AngularJS. I have created a main page with a custom directive for loading a form URL. I want to change the the forms based on a variable in my controller. However, I lost my bindings once I compiled and linked the form from URL
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js"></script>
<div ng-app="tradesman" ng-controller="application" class="form-horizontal" role="form">
Hello {{applicant.name}}
<my-form name="formName">
</my-form>
</div>
var tradesman = angular.module("tradesman")
tradesman.controller("application",function application($scope){
$scope.formName="personals";
$scope.applicant={};
});
tradesman.directive("myForm",function($http,$compile){
return {
restrict:"E",
scope:false,
replace:true,
link:function(scope,element,attrs){
var url="http://tradesman.local/views/"+scope.formName+".html";
$http.get(url).then(function(response){
scope.$watch(function(){
element.html(response.data);
$compile(element.contents())(scope);
});
});
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js"></script>
This has successfully loaded my personals page but lost the binding in that page. More over I want a new form to be loaded whenever I change my formName in controller.
What needs to be done to make form loading and binding work simultaneously

Manage URL when debugging from Visual Studio 2015

I have an asp.net mvc site to which I've added some knockoutjs. The knockout code makes ajax request for data from the controllers e.g.
$.getJSON(BASE_URL + 'MyTasks/GetDataPage', { userKey: vm.UserKey, pageSize: pageSize }, function (returnedPayload) {
data = returnedPayload.filter(function (item) {
return JSON.stringify(item).toLowerCase().indexOf(ft) != -1;
});
self.setPagingData(data,page,pageSize);
The BASE_URL constant I set in the <head> of my layout razor page as follows:
<script type="text/javascript">
var BASE_URL = '/bamportal/';
</script>
All works fine when the website is deployed. However, when I run the website from VS by hitting F5 then I get a 404 such as:
http://localhost:49601/bamportal/MyTasks/GetDataPage?userKey=2&pageSize=50 Failed to load resource
If it had tried to address "http://localhost:49601/MyTasks/GetDataPage" (without the "/bamportal/") it would work.
What's the best solution for this problem?
Quick and dirty:
<script type="text/javascript">
var BASE_URL = '#Constants.BaseUrl';
</script>
where Constants is a static class defined as:
public static class Constants {
#if DEBUG
public const string BaseUrl = "/";
#else
public const string BaseUrl = "/bamportal/";
#endif
}
So when you compile your application in debug configuration you will get /, while in release you will get /bamportal/.
As alternative, a more complex and versatile approach could be obtained using Configuration Transforms and appSettings from Web.config:
<script type="text/javascript">
var BASE_URL = '#System.Configuration.ConfigurationManager.AppSettings["BaseUrl"];';
</script>
This, of course, will be extremely useful in scenarios where you need to deploy front-end and back-end on different domains/urls.
Your code should never know where the site will be hosted, you should use the correct helpers to determine where the action/content is located, this will prevent any issues with paths. Use Url.Content and Url.Action they will generate the correct path/url in the code.
As an example your action needs to point to the "MyTasks", "GetDataPage"
In your razor code you should have something like
<div id="urls" data-url="#Url.Action("ActionMethodName","YourControllerName")"></div>
Then in your get code get that stored url
$.getJSON($("#urls").data("url"),
To elaborate further this code will work on any environment (production, debug, iis, any location) without any developer worry or tweaking with config files or any other process. Tomorrow if you need to host your site on "osportal" not "bamportal" no changes need to be made, this should not be part of your code base.
One of the biggest benefits is that if the controller or action ever change the compiler will let you know that the url does not exist and you can fix it. Hardcoding paths/urls/location is a very bad/unmaintainable practice.

Angular Routing in ASP.NET MVC combined

I m having one index page and one child page. In my index page, I m trying to render my child. but somehow things not working as expected and Angular routing not working as expected
Here is my index page
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<body ng-app="AngularApp">
<div> My message {{message1}} </div>
First child
<div></div>
<div ng-view></div>
</body>
#section scripts{
<script src="~/Scripts/angular.js"></script>
<script src="~/Scripts/angular-route.js"></script>
<script src="~/Scripts/angular-resource.js"></script>
<script src="~/Modules/AngularApp.js"></script>
}
Here is my angularApp.Js file where I have defined the routing
var myapp = angular.module('AngularApp', ['ngRoute']);
myapp.config(function ($routeProvider, $locationProvider) {
$routeProvider.when('/',
{
templateUrl: '/Index',
controller: 'IndexController'
})
.when('/FirstChild',
{
templateUrl: '/Angular/FirstChild',
controller: 'ChildController'
});
$locationProvider.html5Mode(true).hashPrefix('!')
});
myapp.controller('IndexController', function ($scope) {
alert('My Index');
$scope.message1 = "My Index";
});
myapp.controller('ChildController', function ($scope) {
alert('My Child Index');
$scope.FirstMessage = 'My First Message';
});
Here is my ASP.NET MVC Action for rendering the partial view. My controller name in ASP.NET MVC is Angular
public ActionResult FirstChild()
{
return PartialView("Firstchild");
}
Problem 1:
When I run the application with Index as the start page, this is the URL, I m seeing in the browser, http://localhost:59367/Angular/Index but the corresponding controller in Angular side for index page is not triggered
Problem 2:
When I click the First child link in my index page, its taking me to a completely page rather than rendering the partial view inside the ng-view.
http://localhost:59367/Angular/FirstChild
I m pretty sure there is serious problem in Angular routing which I defined but couldn't figure it out:( Please help
Problem Summary:
On further analysis, its been found that, once I click the "First child", ideally the URL should read like Angular/Index#/FirstChild but what happens here is, "ASP.NET MVC Action First Child is getting called and the URL is changing completely"
Problem has been identified. The article which I followed has used the below part
$locationProvider.html5Mode(true).hashPrefix('!')
in the app.js file. I have removed it due to some issues in my local. But while doing so, I didn't update the part in my index page for this line
First child
It has to be
First child
Now angular routing started working fine without any issues. :)
Updated Question:
I tried including the line in d code and I removed as # in my the href but it was not working.. Seems like angular routing has to be updated as well.
$locationProvider.html5Mode(true).hashPrefix('!')
Can someone help me in updating it in the correct format.

ASP.NET MVC Partial View in an AngularJS directive

I'm currently working on an ASP.NET MVC project to which some AngularJS was added - including some AngularJS directives.
I need to add to an AngularJS directive a MVC partial view. Obviously,
#Html.Partial("_PartialView", {{name}})
doesn't work.
So far all my searches online provided no help.
Any idea how I could render a partial view inside an Angular directive?
Thanks!
Angular exists strictly on the client side whereas MVC views exist on the server side. These two cannot interact directly. However, you could create an endpoint in which your partial view is returned as HTML. Angular could call this endpoint, retrieve the HTML, and then include it inside a directive.
Something like this:
app.directive("specialView", function($http) {
return {
link: function(scope, element) {
$http.get("/views/partials/special-view") // immediately call to retrieve partial
.success(function(data) {
element.html(data); // replace insides of this element with response
});
}
};
});
app.directive("myDirective", ['', function () {
return {
restrict: 'A',
scope: {
foo: '='
},
templateUrl: '/home/_myDirectivePartialView',
}]
} }]);
Just need to use templareURL and specify the route to get the partial view.

Resources