I'm trying to implement knockoutjs and requirejs to my asp.net mvc app.
So, here's what I have.
Views/Shared/_Layout.cshtml
<html>
<body>
#RenderBody()
<script src="~/Scripts/require.js" data-main="/Scripts/app/main"></script>
#RenderSection("scripts", required: false)
</body>
<html>
Scripts/main.js
require.config({
baseUrl: '/Scripts',
paths: {
ko: '/Scripts/knockout-3.3.0'
}
});
Views/Product/Index.cshtml (one of my views)
<table class="table">
<thead>
<tr>
<th>Product</th>
<th>Price</th>
<th>Status</th>
</tr>
</thead>
<tbody data-bind="foreach: products">
<tr>
<td data-bind="text: $data.product"></td>
</tr>
</tbody>
</table>
<script src="~/Scripts/app/product.js"></script>
#section scripts {
// Some scripts here
}
Scripts/app/product.js
define(['ko'], function (ko) {
var data = [
{ name: 'Product1' },
{ name: 'Product2' }
];
var Product = function () {
this.name = ko.observable()
};
var productVm = {
products: ko.observableArray([]),
load: function() {
for (var i = 0; i < data.length; i++) {
productVm.products.push(new Product()
.name(data[i].name));
}
}
}
productVm.load();
ko.applyBindings(productVm);
});
Just in case you need to see my folder structure
Solution
- Scripts
-- app
--- product.js
-- require.js
-- knockout-3.3.0.js
- Views
-- Product
--- Index.cshtml
-- Shared
--- _Layout.cshtml
Then, once I navigate to my products index page. I got a define is not define error. What am I missing?
Include following in your main.js
require(["app/product"], function () {
});
And modify index.html as follows
<table class="table">
<thead>
<tr>
<th>Product</th>
<th>Price</th>
<th>Status</th>
</tr>
</thead>
<tbody data-bind="foreach: products">
<tr>
<td data-bind="text: $data.name"></td>
</tr>
</tbody>
</table>
#section scripts {
}
If you intend to use RequireJS for multi page application, then also read this.
Related
How to put content under certain headings?
I have two methods to load data
first axios.get('/api/get/headers')
second axios.get('api/get/contents')
I have no idea how correctly this will be done, given that the headers can be different and the content is correspondingly too
table example
<thead>
<tr>
<th v-for="header in headers" :data-key="header.name">{{ header.title }}</th>
</tr>
</thead>
<tbody>
<tr v-for="content in contents">
<td :data-key="content.name"> {{content.title}}</td>
</tr>
</tbody>
The global problem is that the content can be an array
Here's a one-page example of a way to use axios with Vue.js to get some simple content on the page. Does this help you get started?
<html>
<head>
<script src="http://unpkg.com/vue"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<div class="header">{{headerText}}</div>
<div class="content">{{contentText}}</div>
</div>
</body>
<script>
var vm = new Vue({
el: "#app",
data: function () {
return {
headerText: '',
contentText: ''
}
},
mounted: function () {
axios.get("/api/get/headers").then(response => {
this.headerText = response;
})
.catch(err => {
console.log(err);
});
axios.get("/api/get/content").then(response => {
this.contentText = response;
})
.catch(err => {
console.log(err);
});
}
});
</script>
</html>
Update:
For your specific example, could you go through the list of headers again and match the name property with the content name property, and then display the content? Like so:
<thead>
<tr>
<th v-for="header in headers" :data-key="header.name">{{ header.title }}</th>
</tr>
</thead>
<tbody>
<tr v-for="header in headers">
<td :data-key="header.name"> {{getContent(header.name).title}}</td>
</tr>
</tbody>
<script>
...
methods: {
getContent(name) {
for (var index in this.contents) {
if (this.contents[index].name === name) {
return this.contents[index];
}
}
}
}
...
</script>
I'm starting to learn some AngularJS and am trying to determine its practicality when working along side ASP.NET MVC.
Let's say I have a view which displays beers from a repository in a table. I could output the information in two ways.
1.Using MVC's Razor Engine
Here, the model containing the beers is processed on the server and the html page rendered.
<h3>Rendered using Razor!</h3>
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Colour</th>
<th>Tasted?</th>
</tr>
</thead>
<tbody>
#foreach (var beer in Model)
{
<tr>
<td>#beer.Name</td>
<td>#beer.Colour</td>
<td>#beer.Tried</td>
</tr>
}
</tbody>
</table>
2.Using Angular repeat
Here, the HTML is returned straight away and angular performs a AJAX call to the controller to retrieve its model. After it has that data it outputs it into the table.
<h3>Rendered using Angular!</h3>
<table class="table table-condensed table-striped">
<thead>
<tr>
<th>Name</th>
<th>Colour</th>
<th>Tasted?</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="beer in model">
<td>{{ beer.Name }}</td>
<td>{{ beer.Colour }}</td>
<td>{{ beer.Tried }}</td>
</tr>
</tbody>
</table>
Controller
angular.module('BeerController', [])
.controller('BeerCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.model = {};
$http.get('/Beer/GetBeers').success(function (data) {
$scope.model = data;
});
}]);
My Question
Is there a way to use the Razor engine for the initial load of the data and Angular for everything else (paging calls, searching etc.)? In other words, how do I bind existing html to a controllers model in AngularJS?
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Colour</th>
<th>Tasted?</th>
</tr>
</thead>
<tbody>
<tr>
<td>Fosters</td>
<td>Gold</td>
<td>True</td>
</tr>
<tr>
<td>Becks</td>
<td>Amber</td>
<td>False</td>
</tr>
<tr>
<td>Cobra</td>
<td>Gold</td>
<td>True</td>
</tr>
</tbody>
</table>
In your MVC Controller
public ActionResult Index()
{
var model =.....
//optional
JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() };
ViewBag.data = JsonConvert.SerializeObject(model, Formatting.Indented, jsonSerializerSettings);
return View()
}
In your view Index.cshtml
...
#section Scripts {
//make sure that all anular scripts are loaded before that
<script>
angular.module('BeerController').service('dataService', function () {
var data= #Html.Raw(ViewBag.data);
return {
data:data
}
});
...
</script>
}
Angular Part:
angular.module('BeerController', [])
.controller('BeerCtrl', ['$scope', '$http','dataService', function ($scope, $http,dataService) {
// now you can get data from your dataService without extra trip to your server
$scope.model = dataService.data
....
}]);
index.html:
<div ng-view="myview.html"></div>
myview.html:
<table class="table table-striped table-hover">
<tr>
<td>Name</td>
<td>Product</td>
</tr>
<tr ng-repeat="deal in deals" class="clickableRow">
<td>{{deal.name}}</td>
<td>{{deal.product}}</td>
</tr>
</table>
script.js:
$(document).ready(function($) {
$(".clickableRow").click(function() {
console.log("click");
});
}); // does nothing
console.log($(".clickableRow").length) // returns 0
I want to do some work when the user clicks on the clickableRows rows.
Thanks
why do you mix jquery and angularjs like this ? you can just do it with angularjs
<tr ng-repeat="deal in deals" ng-click="clickRow(deal)">
and in your controller
$scope.clickRow = function(deal) {
console.log(deal)
}
I am working on an application in which I am using knockout Js and I am trying to implement table sorting on clicking the respective columns with jquery.tablesorter.js. in MVC4 Web API
Sorting without knockout Js works fine. I have the code below
1. Index.cshtml
<div class="loadingIndicator" data-bind="visible: loading()"></div>
<table class="newProduct">
<thead>
<tr>
<th><a class="btn btn-success" data-bind="click: add, visible: !loading()">New Product</a>
</th>
</tr>
</thead>
</table>
<link href="#Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Scripts/jquery-1.9.1.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.tablesorter.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.tablesorter.pager.js")" type="text/javascript"></script>
</script>*#
#*<table class="productTable" data-bind="visible: !loading()">*#
<table class="productTable" data-bind="sortTable:true">
<thead>
<tr>
<th>Product</th>
<th>Term</th>
<th>Location</th>
<th>Pipeline</th>
<th>Bid C/P</th>
<th>Bid Volume</th>
<th>Index</th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: canadiancrudes">
<tr> <td data-bind="text: Product"></td>
<td data-bind="text: Term"></td>
<td data-bind="text: Location"></td>
<td data-bind="text: Pipeline"></td>
<td data-bind="text: BidCP"></td>
<td data-bind="text: BidVolume"></td>
<td data-bind="text: Index"></td>
</tr>
<tr></tr>
</tbody>
<tfoot>
<tr>
<th>Product</th>
<th>Term</th>
<th>Location</th>
<th>Pipeline</th>
<th>Bid C/P</th>
<th>Bid Volume</th>
<th>Index</th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</tfoot>
</table>
#section scripts {
<script src="~/Scripts/knockout-2.2.1.js"></script>
<script src="~/App/CustomBindings.js"></script>
<script src="~/Scripts/jquery.signalR-1.0.0.min.js"></script>
<script src="/signalr/hubs"></script>
<script src="~/App/CanadianCrudeViewModel.js"></script>
}
2. View Model
var CanadianCrudeViewModel = function (CanadianContext) {
var self = this;
self.canadiancrudes = ko.observableArray();
self.loading = ko.observable(true);
self.add = function (canadiancrude) {
var payload = {
Term: "Term", Product: "Product" , Location: "Location", Pipeline: "Pipeline",
BidCP: "Bid CP", BidVolume: "Bid Volume", Index: "Index", Bid: "0.0", Offer: "0.0",
OfferVolume:"Offer Volume", OfferCP:"Offer CP"
};
$.ajax({
url: '/odata/Canadiancrudes',
type: 'POST',
// data: ko.toJSON(payload),
data: JSON.stringify(payload),
contentType: 'application/json',
dataType: 'json'
});
}
}
ko.bindingHandlers.sortTable = {
init: function (element, valueAccessor) {
setTimeout(function () {
$(element).addClass('tablesorter');
$(element).tablesorter({ widgets: ['zebra'] });
}, 0);
}
};
For some reasons, I am unable to sort the table when I click on the column and it throws an exception
Uncaught TypeError: Cannot read property '0' of undefined
I know this error usually rises when we try to apply tablesorter for an empty table but in my code, I am binding the data to my table inside the tag.
May I know what mistake I made either while binding or anything else.
I am new to Dust.js and am trying to iterate a JSON object with records and render each of them into a row within a table. Below is the script, I am using to render the table, but am running into issues, I guess while rendering, especially the template argument of the render function. Appreciate if I could be pointed in the right direction
<div id="dustPlaceholder"></div>
<script id="goalTemplate">
<table id="dustGoals">
<thead>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
{#friends}
<tr>
<td>{name}</td>
<td>{age}</td>
</tr>
{/friends}
</tbody>
</table>
</script>
</div>
<script type="text/javascript">
var src = document.getElementById("goalTemplate").innerHTML;
var compiled = dust.compile(src);
dust.render("goalTemplate", { friends: [ { name: "Moe", age: 37}]},
function(err, out) {
document.getElementById('dustPlaceholder').innerHTML = out;
});
</script>
You need to include the entire Dust.js library if you are going to be rendering on the client, so you need to include the dust-full-0.3.0.min.js. Additionally,
<script src="dust-full-0.3.0.min.js"></script>
Also, what is "goalTemplate"?
Also what are you compiling? There are no variables in there. You need to compile the actual HTML - the content in the DIV tag. So everything including the div tags belong in the src variable.
Also, you must assume a name to the compiled template so it can be accessed. I'm really confused what you were doing before, but this example should work:
<script src="dust-full-0.3.0.min.js"></script>
<script type = "text/javascript">
var source = "<div id="dustPlaceholder"></div>
<script id="goalTemplate">
<table id="dustGoals">
<thead>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
{#friends}
<tr>
<td>{name}</td>
<td>{age}</td>
</tr>
{/friends}
</tbody>
</table>
</script>
</div>";
var compiled = dust.compile(src, goalTemplate);
dust.render("goalTemplate", { friends: [ { name: "Moe", age: 37}]},
function(err, out) {
document.getElementById('dustPlaceholder').innerHTML = out;
});
</script>