How to use Vue components (*.vue) in asp.net mvc partial views - asp.net-mvc

I have been trying to get caught up to speed with Vue.js and am working on an asp.net mvc 5 web application that heavily uses jQuery and I would like to start integrating Vue and start replacing jQuery.
I have spent a couple days now trying to integrate Vue into an asp.net mvc 5 web application and with the help of this Best approach when replacing jQuery with VueJS 2 in multi-page existing .NET MVC application, and followed 1_bug's answer.
So in the project that I am hoping to integrate Vue, I am thinking of using components in the partial views first before tackling the the other views.
So in short my question is, how to use Vue components (IE: *.vue files) inside partial views?

I was able to integrate Vue v.2.6 in my ASP.NET Core project without JavaScript bundler using partial views. It should work the same way in a ASP.NET MVC project.
Please check my answer to How do I set up ASP.NET Core + Vue.js? or the sample project on Github for details: ASP.NET Core + Vue.js
I also wrote a step by step description of Using Vue Components in ASP.NET Core at Medium.

This is how I do it. .Vue files are only possible if you use vue-loader (webpack) but as ours is a legacy project, that's not possible
$("vue-category-gallery").each(function () {
new Vue({
el: this,
data: () => ({
action: "",
categoryList: []
}),
beforeMount: function () {
const actionAttribute = this.$el.attributes["data-action"];
if (typeof actionAttribute !== "undefined" && actionAttribute !== null) {
this.action = actionAttribute.value;
} else {
console.error("The data-attribute 'action' is missing for this component.");
}
},
mounted: function () {
if (this.action !== "") {
CategoryService.getGalleryCategoryList(this.action).then(response => {
this.categoryList = response.data;
});
}
},
methods: {
// none
},
template: `
<div class="c-category-gallery" v-if="categoryList.length > 0">
<div class="row">
<div class="col-md-3 col-sm-4" v-for="category in categoryList" :key="category.id">
<div class="c-category-gallery__item">
<img :src="category.imageUrl" :alt="category.name" class="img-responsive"></img>
<div class="c-category-gallery__item-content">
<h4>{{ category.name }}</h4>
<ul class="list-unstyled">
<li v-for="subCategory in category.subCategoryList" :key="subCategory.id">
<a :href="subCategory.categoryUrl" v-if="subCategory.showCategoryUrl">{{ subCategory.name }}</a>
</li>
</ul>
<a :href="category.categoryUrl" v-if="category.showCategoryUrl">{{ category.detailName }}</a>
</div>
</div>
</div>
</div>
</div>`
});
})
Calling it from HTML goes as follows...
<vue-category-gallery
data-action="/api/categories/getcategorygallerylist?itemCount=4"
v-cloak></vue-category-gallery>
I am currently looking into Vue.component("", ...) but that's still in testing :)
EDIT:
With Vue.component("", ...)
Vue.component("vue-person", {
props: ["name"],
data: function () {
return {
type: "none",
age: 0
}
},
template: `<div>
<p>My name is {{name}}.</p>
<p>I am {{type}} and age {{age}}.</p>
</div>`
})
var vm = new Vue({
el: "vue-components",
components: [
"vue-person"
]
})
$(".js-change-value").on("click", function () {
vm.$refs.myPersonComponent.type = "human";
vm.$refs.myPersonComponent.age = 38;
})
<vue-components>
<vue-person name="Kevin" ref="myPersonComponent"></vue-person>
<button type="button" class="js-change-value">Change value</button>
</vue-components>
I would love to be able to omit the wrapper but as I'm already using other instances (new Vue()) on my page, I couldn't use for example '#main' (being the id on the body element) as it clashes with other global instances I already have on my page.

Related

Ajax.ActionLink alternative with mvc core

In MVC5 there is #Ajax.ActionLink that is useful to update just a partial view instead of reloading the whole View. Apparently in MVC6 is not supported anymore.
I have tried using #Html.ActionLink like the following but it doesn't update the form, it return just the partial view:
View:
#Html.ActionLink("Update", "GetEnvironment", "Environments", new { id = Model.Id }, new
{
data_ajax = "true",
data_ajax_method = "GET",
data_ajax_mode = "replace",
data_ajax_update = "environment-container",
#class = "btn btn-danger"
})
control:
public async Task<ActionResult> GetEnvironment(int? id)
{
var environments = await _context.Environments.SingleOrDefaultAsync(m => m.Id == id);
return PartialView("_Environment",environments);
}
Partial view:
#model PowerPhysics.Models.Environments
this is a partial view
Then I tried using ViewComponents. When the page loads the component works correctly but I don't understand how to refresh just the component afterward (for example with a button):
View:
#Component.InvokeAsync("Environments", new { id = Model.Id }).Result
component:
public class EnvironmentsViewComponent : ViewComponent
{
public EnvironmentsViewComponent(PowerPhysics_DataContext context)
{
_context = context;
}
public async Task<IViewComponentResult> InvokeAsync(int? id)
{
var environments = await _context.Environments.SingleOrDefaultAsync(m => m.Id == id);
return View(environments);
}
}
How can I update just a part of a view by using PartialViews in MVC6?
You can use a tag as follows:
<a data-ajax="true"
data-ajax-loading="#loading"
data-ajax-mode="replace"
data-ajax-update="#editBid"
href='#Url.Action("_EditBid", "Bids", new { bidId = Model.BidId, bidType = Model.BidTypeName })'
class="TopIcons">Link
</a>
Make sure you have in your _Layout.cshtml page the following script tag at the end of the body tag:
<script src="~/lib/jquery/jquery.unobtrusive-ajax/jquery.unobtrusive-ajax.js"></script>
ViewComponent's are not replacement of ajaxified links. It works more like Html.Action calls to include child actions to your pages (Ex : Loading a menu bar). This will be executed when razor executes the page for the view.
As of this writing, there is no official support for ajax action link alternative in aspnet core.
But the good thing is that, we can do the ajaxified stuff with very little jQuery/javascript code. You can do this with the existing Anchor tag helper
<a asp-action="GetEnvironment" asp-route-id="#Model.Id" asp-controller="Environments"
data-target="environment-container" id="aUpdate">Update</a>
<div id="environment-container"></div>
In the javascript code, just listen to the link click and make the call and update the DOM.
$(function(){
$("#aUpdate").click(function(e){
e.preventDefault();
var _this=$(this);
$.get(_this.attr("href"),function(res){
$('#'+_this.data("target")).html(res);
});
});
});
Since you are passing the parameter in querystring, you can use the jQuery load method as well.
$(function(){
$("#aUpdate").click(function(e){
e.preventDefault();
$('#' + $(this).data("target")).load($(this).attr("href"));
});
});
I add ajax options for Anchor TagHelper in ASP.NET MVC Core
you can see complete sample in github link :
https://github.com/NevitFeridi/AJAX-TagHelper-For-ASP.NET-Core-MVC
after using this new tagHelper you can use ajax option in anchor very easy as shown below:
<a asp-action="create" asp-controller="sitemenu" asp-area="admin"
asp-ajax="true"
asp-ajax-method="get"
asp-ajax-mode="replace"
asp-ajax-loading="ajaxloading"
asp-ajax-update="modalContent"
asp-ajax-onBegin="showModal()"
asp-ajax-onComplete=""
class="btn btn-success btn-icon-split">
<span class="icon text-white-50"><i class="fas fa-plus"></i></span>
<span class="text"> Add Menu </span>
</a>
Use tag helpers instead and make sure to include _ViewImport in your views folder.
Note: Make sure to use document.getElementsByName if there are several links pointing to different pages that will update your DIV.
Example - Razor Page
<script type="text/javascript" language="javascript">
$(function () {
var myEl = document.getElementsByName('theName');
$(myEl).click(function (e) {
e.preventDefault();
var _this = $(this);
$.get(_this.attr("href"), function (res) {
$('#' + _this.data("target")).html(res);
});
});
});
</script>
<a asp-action="Index" asp-controller="Battle" data-target="divReplacable" name="theName" >Session</a>
<a asp-action="Index" asp-controller="Peace" data-target="divReplacable" name="theName" >Session</a>
<div id="divReplacable">
Some Default Content
</div>

Live search MVC

I'm looking for live search for ASP.NET and entity framework. I'm a little bit green with it. I read that it needs to use ajax, but I never used it before and can't get good example. Here is a piece of code, cshtml (part of textbox)
<div class="form-horizontal">
<hr />
<h4>Search for a client: </h4>
<div class="input-group">
<span class="input-group-addon" id="Name">
<span class="glyphicon glyphicon-user" aria-hidden="true"></span>
</span>
#Html.TextBox("Name", "", new { #class = "form-control", placeholder = "Name" })
</div>
<div><h6></h6></div>
<div class="input-group">
<span class="input-group-addon" id="Surname">
<span class="glyphicon glyphicon-user" aria-hidden="true"></span>
</span>
#Html.TextBox("Surname", "", new { #class = "form-control", placeholder = "Surname" })
</div>
<div><h6></h6></div>
<button type="submit" class="btn btn-default" data-toggle="modal" data-target="#infoModal">Search</button>
</div>
this is a part of controller:
public ActionResult Index(string Name, string Surname)
{
var SearchList = from m in db.Klienci
select m;
if (!String.IsNullOrEmpty(Name))
{
SearchList = SearchList.Where(s => s.Name.Contains(Name));
}
if (!String.IsNullOrEmpty(Surname))
{
SearchList = SearchList.Where(s => s.Nazwisko.Contains(Surname));
}
return View(SearchList);
}
So it search for me clients by name and surname, but it refresh full page when it lost focus or after clicking the button. How to solve it, to get live search? after each keystroke search through database? I'm a little bit green, would you Help me?
You can listen to the keyup event on your input element, read the value and send it to the server using ajax. Return the results and in the ajax call's success callback, update the ui with the results.
$(function() {
$("#Name,#SurName").keyup(function(e) {
var n = $("#Name").val();
var sn = $("#SurName").val();
$.get("/Home/Index?Name="+n+"&SurName="+sn,function(r){
//update ui with results
$("#resultsTable").html(r);
});
});
});
The code basically listens to the key up event on the two input textboxes and read the values and send to the /Home/Index action method using jquery get method asynchronously.When the action method returns the response, we update the DOM.
Assuming resultsTable is the Id of the table where we list the results.
Also, since you are returning the partial view result ( without layout headers), you should use return PartialView() instead of return View()
if(Request.IsAjaxRequest())
return PartialView(SearchList);
return View(SearchList);
Here is nice example/tutorial how to use Ajax with ASP.NET MVC
http://www.itorian.com/2013/02/jquery-ajax-get-and-post-calls-to.html
EDITED: 2016-07-20
Example:
$(function () {
$("searchField").keyup(function () {
$.ajax({
type: "POST",
url: "/Controller/Action",
data: data,
datatype: "html",
success: function (data) {
$('#result').html(data);
}
});
});
You have to visit the server to get data from server and without ajax it is not possible. Now the question is how to make ajax call, you can use jQuery js lib to do but I would recommend you to try angular as data binding in angular will fulfill your needs.
Take a look at followings links
Angular Ajax Service -
jQuery Ajax

How to run Angular JS on after page load rendered html?

I'm developing asp.net mvc a project with angular js.
I'm working on tabs and install related partial view after click event.
I am sending with partial view html of the json to main page but angular codes doesn't work on the page
What can i do?
Sample Problem
html:
<div ng-app="MyAppS">
<div ng-controller="AnaTest">
<button id="btn1" ng-click="btn1Click()">click</button>
</div>
<div id="m_area">
</div>
<br />{{ 'Hello Angular' }}</div>
javascript:
var m_app = angular.module('MyAppS', []);
function AnaTest($scope) {
$scope.btn1Click = function () {
var runtimeBtn = angular.element("<button ng-click=\"btn2Click()\">Help Me! </button>");
$('#m_area').html(runtimeBtn);
};
$scope.btn2Click = function(){
debugger;
alert('Why can not show?!');
};
};
m_app.controller('AnaTest', AnaTest);
You need to $compile it:
var runtimeBtn = $compile(angular.element("<button ng-click=\"btn2Click()\">Help Me!</button>"))($scope);
See it here: http://jsfiddle.net/7yqrjdkk/8/
However, a more "Angular" way to do it would be putting it under the same controller/scope and simply using ng-show, like this: http://jsfiddle.net/7yqrjdkk/9/

Multiple ViewModels with Knockout and ASP.NET MVC4 SPA

I'm new to ASP.NET MVC SPA and Knockout.js os maybe it's a simple mistake I made...
Situation: I have two partialviews in my website and I want that every partialview has his own Knockout ViewModel so I won't get a huge ViewModel.
My current ViewModel:
/// <reference path="../_references.js" />
function MobileDeliveriesViewModel() {
var self = this;
// Data
self.currentDelivery = ko.observable();
self.nav = new NavHistory({
params: { view: 'deliveries', deliveryId: null }
});
// Test
self.foo = "FooBar"
self.bar = "BarFoo"
self.nav.initialize({ linkToUrl: true });
// Navigate Operations
self.showDeliveries = function () { self.nav.navigate({ view: 'deliveries' }) }
self.showCustomers = function () { self.nav.navigate({ view: 'customers' }) }
}
function BarFooViewModel() {
var self = this
//MobileDeliveriesViewModel.call(self)
self.bar2 = "BarFooTwo"
}
ko.applyBindings(new MobileDeliveriesViewModel());
ko.applyBindings(new MobileDeliveriesViewModel(), $('#BarFoo')[0]);
ko.applyBindings(new BarFooViewModel(), document.getElementById('BarFoo'));
My Index.cshtml:
<div data-bind="if: nav.params().view == 'deliveries'">
#Html.Partial("_DeliveriesList")
</div>
<div class="BarFoo" data-bind="if: nav.params().view == 'customers'">
#Html.Partial("_CustomersList")
</div>
<script src="~/Scripts/App/DeliveriesViewModel.js" type="text/javascript"></script>
My CustomerPartialView:
<div id="BarFoo" class="content">
<p data-bind="text: bar"></p>
<p data-bind="text: bar2"></p>
<button data-bind="click: showDeliveries, css: { active: nav.params().view == 'deliveries' }">Deliveries</button>
</div>
My DeliveriesPartialView:
<div class="content">
<p data-bind="text: foo"></p>
<button data-bind="click: showCustomers, css: { active: nav.params().view == 'customers' }">Customers</button>
</div>
If I run this, it won't recognize the bar2 propertie in my BarFooViewModel...
I have tried 2 different applyBindings at the end of my ViewModel.
Anybody got an idea or is their a better way/pattern to do this?
are there JS errors on page?
nav.params().view
but params: { view: 'deliveries', deliveryId: null } - it's not function.
and if you want use a few view models on single page - check this http://www.knockmeout.net/2012/05/quick-tip-skip-binding.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+KnockMeOut+%28Knock+Me+Out%29 acticle. you have to use "stopBinding"
It looks like you are applying multiple data bindings to the same sections.
ko.applyBindings(new MobileDeliveriesViewModel();
This will bind to all elements one the page.
ko.applyBindings(new MobileDeliveriesViewModel(), $('#BarFoo')[0]);
this will try to bind to all elements inside the div
ko.applyBindings(new BarFooViewModel(), document.getElementById('BarFoo'));
This will also try to bind to all elements inside the div.
To keep things simple, you should try to bind a single view model to a single html section. I've found that trying to bind two view models in the same html section has been hard to get work correctly and trouble shoot.
Jack128's answer also makes some good points.

Show different web pages in multi view using link button

I have developed a web site on ASp.net 3.5 with VB which have multiple pages the problem is i want to show all pages in one view user click on link button and coprresponding page should open on single page then user click to other link button and another page open in same browser window with same layout.Please suggest me what should i do?
You could use AJAX to achieve this. So for example let's suppose that you have multiple controller actions that return partial views. You could then create links on your page to those actions:
<%= Html.ActionLink("page 1", "Page1", "SomeController", null, new { id = "link1" }) %>
<%= Html.ActionLink("page 2", "Page2", "SomeController", null, new { id = "link2" }) %>
<%= Html.ActionLink("page 3", "Page3", "SomeController", null, new { id = "link3" }) %>
and 3 corresponding placeholders where the pages would be loaded:
<div id="page1" />
<div id="page1" />
<div id="page1" />
you could now AJAXify those links in a separate javascript file. Example with jquery:
$(function() {
$('#link1').click(function() {
$('#page1').load(this.href);
return false;
});
$('#link2').click(function() {
$('#page2').load(this.href);
return false;
});
$('#link3').click(function() {
$('#page3').load(this.href);
return false;
});
});
I would also strongly recommend you going through the tutorials on the ASP.NET MVC site.

Resources