Reputation: 411
I have a script in my header that is calling a web api which should populate a view model. This is below.
@using GigHub.Controllers
@using GigHub.ViewModel
@model GigHub.ViewModel.ProjectsViewModel
@{
ViewBag.Title = "Projects";
}
<head>
<script>
(function getProjects() {
$.get("/api/projects")
.done(function () {
alert("Got Projects");
})
.fail(function () {
alert("Something failed!");
});
});
</script>
</head>
I then have my html that would loop through the viewModel and set it up throughout the html, but every time it gets run, it is throwing a null reference exception to Model.ProjectList in the for each because it hasn't populated yet. I thought putting the script in the header would let it run first, but that doesn't seem to be the case.
<h2>Projects</h2>
<ul class="gigs voffset4" style="width: 600px;">
@foreach (var project in Model.ProjectList)
{
<li>
<div class="date">
<div class="month">
@project.Name
</div>
<div class="day">
@project.Key
</div>
</div>
<div class="details">
<span class="artist">
@project.Id
</span>
<span class="genre">
@project.ProjectTypeKey
</span>
</div>
</li>
}
</ul>
Here is my actual projectsController
public class ProjectsController : Controller
{
private readonly string m_Username = Properties.Settings.Default.username;
private readonly string m_Password = Properties.Settings.Default.password;
public ActionResult Index()
{
var client = new RestClient("https://example.net/rest/api/2/");
client.Authenticator = new HttpBasicAuthenticator(m_Username, m_Password);
var request = new RestRequest("project/", Method.GET);
request.RequestFormat = DataFormat.Json;
request.OnBeforeDeserialization = resp => { resp.ContentType = "application/json"; };
var response = client.Execute<List<Project>>(request);
var content = response.Content; // raw content as string
if (content == null)
throw new Exception(response.ErrorMessage);
var projectArray = JsonConvert.DeserializeObject<List<Project>>(response.Content);
var viewModel = new ProjectsViewModel()
{
ProjectList = projectArray,
Heading = "Projects"
};
return View("Projects", viewModel);
}
}
Upvotes: 0
Views: 40
Reputation: 218732
You are trying to mix javascript and C# code together and expecting it to work! No. It does not work that way.
The c# code in your view ( the foreach
block) gets executed by razor in the server and the resulted html markup will be send to the client browser. That means, if you are accessing Model.ProjectList
in your view, you should make sure that you are passing a model to your view with that property(ProjectList
).
You have 2 options.
In your get action, create an object of your view model, set the ProjectList
property and send it to view.
public ActionResult Index()
{
var vm = new YourViewModel();
vm.ProjectList= GetListOfProjectsFromSomeWhere();
return View(vm);
}
private List<ProjectItem> GetListOfProjectsFromSomeWhere()
{
var list=new List<ProjectItem>();
list.Add(new ProjectItem { Name="Project 1"}); // Replace with real data here
return list;
}
Assuming you have a view model called YourViewModel as below
public class ProjectItem
{
public string Name {set;get;}
}
public class YourViewModel
{
public List<ProjectItem> ProjectList {set;get;}
}
and and make sure your razor view is strongly typed to this view model
@model YourViewModel
<h2>Projects</h2>
@foreach (var project in Model.ProjectList)
{
<p>@project.Name</p>
}
From your client side code,make the call to your api(like you did) and parse the response and update the DOM.
You need to create a container element in your view so that your javascript code can append items to that from the api call result.
<ul id="projects"></ul>
Now make sure that your javscript code will execute on the document ready event.
function getProjects() {
$.get("/api/projects")
.done(function (data) {
var projectHtml="";
$.each(data,function(i,item){
projectHtml+="<li>"+item.Name+"-"+item.Key+"</li>";
});
$("#projects").html(projectHtml);
})
.fail(function () {
alert("Something failed!");
});
}
$(function(){
getProjects();
});
Assuming your api call returns an array of item, each with a Name
& Key
property like this
[{Name:"Project1", Key:"Pr1"},{Name:"Project2", Key:"Pr2"}]
Upvotes: 1