Monzingo
Monzingo

Reputation: 411

JavaScript isnt getting called before the Html

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

Answers (1)

Shyju
Shyju

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.

1. Full server side approach

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>
} 

2. Use ajax to load page content.

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

Related Questions