In an Umbraco MVC partial view I have declared a parameter of type List, based on a custom model.
List<MyModel> modelList = new List<MyModel>();
public class MyModel{
public int ArticleID { get; set; }
public string ArticleName { get; set; }
public string ArticleType { get; set; }
public bool isSelected { get; set; }
}
That list get populated with data from another model before being rendered in a row.
On a button click even I want to take that list and loop through it, any rows which have been selected have to be added to another list, the problem is I can't seem to access it in a function on the same view.
Here's what I have at the moment, I'm fine with populating the other list so I just put an alert in and put a breakpoint on it to see what is in modelList, but I get the error "AddToList is not defined" and I think it's to do with how I'm trying to access the list.
Can anyone tell me how I should be doing this please?
function AddToList() {
$.each(#modelList, function () {
alert("function hit");
});
}
First you need to convert your server side model into javascript array, after that you can perform each operation on it.
function AddToList()
{
var data = #Html.Raw(Json.Encode(Model));
$.each(data, function () {
alert("function hit");
});
}
Related
I have two models, Model1 and Model2. The Model1 has an atribute that is a list of my model2. I need to access those attributes in my index class. I'm not sure how to do that. Here is Model1:
public class Model1
{
public Model1()
{
List1 = new HashSet<Model2>();
}
[Key]
public int Id { get; set; }
public virtual ICollection<Model2> List1 { get; set; }
}
Here is Model2:
public class Model2
{
[Key]
public int Id { get; set; }
public string Latitude { get; set; }
public string Longitude { get; set; }
}
here is part of my Index:
$.each(data, function (i, item) {
var infowindow = '<div id="content" style="hight:700px; width:500px">' +
'<div id="siteNotice">' +
'</div>' +
'<div id="bodyContent">' +
'<p><b>ABC:</b></p>' +
$.each(item.List1, function (f, item1) {
'<p>Latitude:'+ item1.Latitude+'</p>'
});
//MORE CODE
});
});
});
The code that I have above is supposed to appear on a infowindow. I want to show the latitude in a paragraph. I'm trying to do it by accessing the list. However, it gives me an 'undefined' and the paragraph doesn't even appear.
I'm not sure how to explain it. But I hope from the code you'll understand.
While you can certainly inject your model information into javascript, I feel that you should step back and ask yourself if you really need to?
There may be edge cases where you have no choice but more than likely you will cause more headaches down the line.
Generating markup via HTML from your model, i would argue, is counter productive. Why not just render the markup directly in your razor:
#foreach (var x in Model.List1 )
{
<p>Latitude: #x.Latitude+</p>
}
Alternatively, if you really need to use the data in javascript, i would consider using an ajax call to obtain the data. Since your'e using jquery :
$.get( "/myController/GetStuff" )
.done(function(data) {
console.log(data);
//other code
})
.fail(function(err) {
console.error(error);
})
.always(function() {
//hide loading animation or something
});
I have a basic entity class in .NET API that is combined with a front-end angular framework. I have two classes, project and company. When creating a project, I need to assign a company. The company is not saved when sending a POST request to the projects controller.
the class is:
public class Project
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public Company Company { get; set; }
public Contact Contact { get; set; }
public User2 User { get; set; }
}
The controller method is:
// POST: api/Projects
[ResponseType(typeof(Project))]
public IHttpActionResult PostProject(Project project)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Projects.Add(project);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = project.Id }, project);
}
the json POST data is here
{
"name":"project name",
"description":"text description",
"company":{"id":"1"},
"contact":{"id":"1"},
"user":{"id":"1"}
}
Why are the id's for company, contact, user, not updating the foreign key tables? What value is needed to pass into the controller method to save the foreign key?
A foreign key, means that it's value depends on the value from the parent table.
Meaning, The value to insert it the column on which it depends on from the parent table.
from Tutorials Point:
A foreign key is a key used to link two tables together. This is
sometimes also called as a referencing key.
A Foreign Key is a column or a combination of columns whose values
match a Primary Key in a different table.
The relationship between 2 tables matches the Primary Key in one of
the tables with a Foreign Key in the second table.
If a table has a primary key defined on any field(s), then you cannot
have two records having the same value of that field(s).
So in order to solve your problem and correct your code, you will have to know what is the value of the primary key which the column depends on from the parent table.
Thus is the constraint error as well.
In case I need this again. The related entity must be retreived by the db context before saving it or else it will create a new related entity.
When passing in only the ID as the property, retrieve the related entity from the db first.
// POST: api/Projects
[ResponseType(typeof(Project))]
public IHttpActionResult PostProject(Project project)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Projects.Add(project);
project.Company = db.Companies.First(x => x.Id == project.Company.Id);
project.User = db.User2.First(x => x.Id == project.User.Id);
project.Contact = db.Contacts.First(x => x.Id == project.Contact.Id);
try
{
db.SaveChanges();
}
catch (Exception e)
{
Debug.Write(e);
}
return CreatedAtRoute("DefaultApi", new { id = project.Id }, project);
}
I have a website served from a proprietary C++ server.
There is a standard javascript ajax function in the code but I don't want to start editing it.
The actual sending bit is as follows:
this.send=function(myawesomemodel)
{
/*Code redacted for brevity*/
obj.req.open('POST',myawesomeurl,true);
obj.req.setRequestHeader('Content-type','application/x-www-form-urlencoded');
obj.req.send(JSON.stringify(myawesomemodel));
}
It used to send key value pairs as a query string but now it needs to send json.
I can send this function a controller/action address (myawesomeurl) for the appropriate end point and I can send it an awesome object which will be accepted by the action as a basic C# Model (myawesomemodel):
public ActionResult myawesomeaction(MyAwesomeClass myawesomeclass)
{
}
For the .Net model:
public class MyAwesomeClass
{
public int A { get; set; }
public int B { get; set; }
public string C { get; set; }
}
How do I build a javascript object the controller will recognise please?
Here's my latest failure:
function MyAwesomeModel()
{
this.A=1;
this.B=2;
this.C='Three';
}
Then:
var anawesomemodel=new MyAwesomeModel();
myawesomeajaxmodel.send(anawesomemodel);
I cannot construct the correct object in plain javascript so the mvc action registers it, what's the correct method please?
var myawesomemodel = {
A : 1,
B : 2,
C : 'Three'
}
For anyone else with the same problem who finds this page, Stephen Muecke nailed it
Change the ajax object to:
this.send=function(myawesomemodel)
{
/*Code redacted for brevity*/
obj.req.open('POST',myawesomeurl,true);
obj.req.setRequestHeader('Content-type','application/json;charset=utf-8');
obj.req.send(JSON.stringify(myawesomemodel));
}
I am building an online test webapp in asp.net mvc4.And I need to make the user to navigate between previous and next questions (only 1 question at a time). I have a layout which has a countdown timer in it. I have a question & options list as a model in the view and I need to navigate the list via previous and next buttons. The layout must remain same since it has a timer in it. When the user clicks on 'next', the current question should get back to list along with chosen answer (via radio buttons) and the next question from the list should be displayed. Similar function is done by previous button also. Can anyone please suggest a solution in Ajax,Json or Javascript ?
The view:StartTest
#model LoginTrial3.Models.QuestionPaper
#{
ViewBag.Title = "StartTest";
Layout = "~/Views/Shared/_LayoutTest.cshtml";
}
<h2>StartTest</h2>
Model : QuestionPaper
public class QuestionPaper
{
public List<object> RandomQuestionList = new List<object>();
//generate the maps to hold the answers
public Dictionary<int, string> AptiAnsList = new Dictionary<int, string>();
public Dictionary<int, string> TechAnsList = new Dictionary<int, string>();
//define a ctor
public QuestionPaper(List<object> QList)
{
foreach(var item in QList)
{
RandomQuestionList.Add(item);
}
}
}
each object in QList is of a AptiQuestionType :
public class AptiQuestion
{
public int Id { get; set; }
public string Question { get; set; }
public string OptionA { get; set; }
public string OptionB { get; set; }
public string OptionC { get; set; }
public string ExpectedAnswer { get; set; }
}
A solution without ajax could be to extend the model class and add ids of the previous and next items, then in the view render links using these ids.
I'm working on a project using Breeze and I came across a problem with some entities I had created using a one-to-one relationship. This is a bit of a long story, but it has a happy ending, so bear with me :)
Here is a cut down version my C# code:
public class Person {
[Key]
public int Id { get; set; }
public virtual User User { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class User {
[Key]
public int Id { get; set; }
[Required]
public virtual Person Person { get; set; }
[Required]
public string EmailAddress { get; set; }
[Required]
public string Password { get; set; }
}
public class MyDbContext : DbContext {
public DbSet<Person> Person { get; set; }
public DbSet<User> User { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Entity<User>().HasRequired(x => x.Person);
}
}
This creates a Persons database table with an auto generated primary key, and a Users table with a manually entered primary key, which is a subset of the Persons table.
I create these entities, and attempt to save them in my javascript code with something like:
var manager = new breeze.EntityManager('api/Db');
// other breeze initialization stuff, metadata etc.
var person=manager.createEntity('Person', undefined, breeze.EntityState.Detached);
var user=manager.createEntity('User', undefined, breeze.EntityState.Detached);
// set other fields, name, email, password
user.Person(user);
manager.addEntity(user);
manager.saveChanges().then(function() { // etc
When the SaveChanges function is called in my BreezeController I get this exception:
Validation error: Property: 'Person', Error: 'The Person field is required.'
Upon examination of the JSON that is send to the BreezeController I find that the Id of both the Person and the User was '-1', and that the JSON did not nest the Person entity inside the Person property of the User. So there was no way for the EFContextProvider to know that there was supposed to be a relationship between these objects.
My first attempt to solve this was to send the 'Person' entity to the backend with saveChanges, then send the 'User' in a seperate transaction. Eg:
manager.addEntity(person);
manager.saveChanges().then(function() {
user.Person(user); // this line moved from previous example,
// breeze throws error here
manager.addEntity(user);
manager.saveChanges().then(function() { // etc
Using this approach I got this error from breeze.js:
Cannot attach an object to an EntityManager without first setting its key
or setting its entityType 'AutoGeneratedKeyType' property to something other
than 'None' at checkEntityKey (http://localhost:12151/scripts/breeze.debug.js)
So I tried to set the key on the User to be the value filled in when the Person was saved. Using "user.Id(person.Id);" Now in the BreezeController I still get the same error:
Validation error: Property: 'Person', Error: 'The Person field is required.'
Next I tried to modify the SaveChanges method of my BreezeController to check for an incoming 'User' object which doesn't have a 'Person' property set, then Find the person in the database, and assign it to the Person before calling _efContextProvider.SaveChanges(saveBundle); I lost the code for exactly how I did this, but it's irrelevant as it didn't work properly either... It created a SECOND 'Person' in the database, exactly the same as the one that was saved in the first manager.saveChanges, but it had a new primary key generated. This did however successfully associate the second Person with the User.
After thinking about it overnight I came up with a working solution by subclassing the EFContextProvider with this:
public class MyEfContextProvider : EFContextProvider<MyDbContext>
{
protected override Dictionary<Type, List<EntityInfo>> BeforeSaveEntities(
Dictionary<Type, List<EntityInfo>> saveMap)
{
AssociateOneToOne(saveMap, typeof(Person), typeof(User));
return saveMap;
}
private static void AssociateOneToOne(IReadOnlyDictionary<Type,
List<EntityInfo>> saveMap, Type parent, Type child)
{
if (!(saveMap.ContainsKey(parent) && saveMap.ContainsKey(child))) return;
Func<EntityInfo, object> idFunc = delegate(EntityInfo info)
{
var o = info.Entity;
return o.GetType().GetProperty("Id").GetValue(o);
};
var childProp = child.GetProperty(parent.Name);
var childMap = saveMap[child].ToDictionary(idFunc, info => info.Entity);
var parentMap = saveMap[parent].ToDictionary(idFunc, info => info.Entity);
foreach (var childEntry in childMap)
{
childProp.SetValue(childEntry.Value, parentMap[childEntry.Key]);
}
}
}
Now I realise this has been a long question, and thanks for reading. But the only question I have is, why do I have to do it this way? Is this something that Breeze doesn't have implemented yet? If so, is the way I've done it ok?
You've uncovered a bug ... or so it seems to me. I have filed it and we'll let you know when it is fixed.
On a different note, your BreezeJS client code is a little more tortured than it needs to be. Why create an uninitialized detached entity ... and then add it?
The line user.Person(user); doesn't seem right at all. That should fail. I think you meant user.Person(person);. But you won't need that either.
Try this:
var manager = new breeze.EntityManager('api/Db');
// other initialization stuff.
// adds new, initialized Person entity
var person = manager.createEntity('Person', {
// perhaps init fields: firstName, lastName
});
// adds new, initialized User entity, associated w/ parent Person
var user = manager.createEntity('User', {
personId: person.Id(), // SETS THE KEY TO PARENT PERSON
// perhaps init fields: emailAddress, password (really!?!)
});
manager.saveChanges().then(function() { ... etc.
Update 8 May 2013
Yes, that commit is the fix on the BreezeJS side. We'll release it soon ... although of course you are free to grab an intermediate commit. I wouldn't ... because intermediate, untagged commits haven't been properly QA'd.
I think you will still have a problem ... this time on the EntityFramework side. 1-1 is pretty trick in Code First; you may want to look at this StackOverflow thread.
To be specific to your case, I think you need to change your definition of User to this:
public class User {
[Key]
[ForeignKey("Person")]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
//[Required]
public virtual Person Person { get; set; }
[Required]
public string EmailAddress { get; set; }
[Required]
public string Password { get; set; }
}
You shouldn't need the "Fluent API" mapping for User that you show above and it might get in the way.
// DELETE THIS !!!
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Entity().HasRequired(x => x.Person);
}
FWIW, the Order/InternationalOrder relationship in DocCode is virtually the same as your Person/User. The test, "can save a new Northwind Order & InternationalOrder [1..(0,1) relationship]", in the saveNorthwindTests.js confirms the model definition and the Breeze fix.
Hope this helps.
Breeze v 1.3.3 is now available on the Breeze website and we did fix an issue with 1-1 mappings. Could you confirm whether this corrects your issue?