i have a problem with my model.
I need send a list of another object to my controller, but i dont know how to create this object using AngularJS.
I have three input field, homePhone, cellphone and contact, all fields are about phone, and my ClientModel has a list of phones. What i want to do, is get this three fields and include in a list inside client model.
**MVC Model "Client"**
public int Id { get; set; }
public string Name { get; set; }
public string Email{ get; set; }
public IEnumerable<Phone> Phones { get; set; }
**MVC Model "Phone"**
public int PhoneId { get; set; }
public int ClientId { get; set; }
public int PhoneType { get; set; }
public string Number { get; set; }
View
<div class="form-group col-lg-4">
<label>Home Phone</label>
<input class="form-control" ng-model="?">
</div>
<div class="form-group col-lg-4">
<label>Cellphone</label>
<input class="form-control" ng-model="?">
</div>
<div class="form-group col-lg-4">
<label>Contact Phone</label>
<input class="form-control" ng-model="?">
</div>
<button class="btn btn-primary" style="float: right" ng-click="saveClient(client)">Confirmar</button>
Controller JS
$scope.saveClient = function(client) {
clientesAPI.saveCliente(client).success(function() {
alert('OK');
}).error(function () {
alert('Error');
});`enter code here`
}
What you could do is create actual Constructor functions in JS and consistently model you current Server Side MVC Model.
So is would look something like this ...
angular.module('app', [])
.factory('Client', function() {
return Client;
function Client() {
this.id = 0;
this.name = '';
this.email = '';
this.phones = [];
}
Client.prototype.init = function(client) {
this.id = client.id;
this.name = client.name;
this.email = client.email;
this.phones = [];
}
})
.factory('Phone', function() {
return Phone;
function Phone() {
this.phoneId = 0;
this.clientId = 0;
this.phoneType = 'Default Phone Type';
this.number = 0;
}
Phone.prototype.init = function(phone) {
this.phoneId = phone.phoneId;
this.clientId = phone.clientId;
this.phoneType = phone.phoneType;
this.number = phone.number;
}
})
.factory('clientService', function($http, $log, Client, Phone) {
var service = {
getClient: getClient,
saveClient: saveClient
};
return service;
//////////////////////////
function getClient() {
return $http.get('clientApi')
.then(success)
.catch(error)
// This is where defining actual JS Quote unQuote Classes comes in handy
function success(response) {
var clients = response.data;
angular.forEach(clients, function(client) {
client = new Client().init(client);
angular.forEach(client.phones, function(phone) {
phone = new Phone().init(phone);
})
})
return clients;
}
function error(response) {
$log.error('Error getting Clients: ' + response.data);
}
}
function saveClient(client) {
return $http.post('clientApi', client)
.then(success)
.catch(error)
// This is where defining actual JS Quote unQuote Classes comes in handy
function success(response) {
$log('Saved Client Successfully');
}
function error(response) {
$log.error('Error saving Client: ' + response.data);
}
}
})
// I would use Controller As Syntax normally
.controller('clientController', function($scope, clientService, Client, Phone) {
$scope.client = new Client();
$scope.client.phones.push(new Phone());
$scope.savedClient;
$scope.saveClient = function() {
$scope.savedClient = $scope.client;
alert('Yeah we saved some data!!');
//Unconmment this to access the real service, Nowhere to call here :-)
//clientService.saveClient($scope.client);
};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="clientController">
<!-- Use ngRepeat to simplify things a bit -->
<div class="form-group col-lg-4" ng-repeat="phone in client.phones track by phone.phoneId">
<label>{{phone.phoneType}}</label>
<input class="form-control" ng-model="phone.number">
</div>
<!-- You will already have access to the updated model in you controller -->
<button class="btn btn-primary" style="float: right" ng-click="saveClient()">Confirmation</button>
<!--Display Saved Data-->
<pre>{{savedClient | json}}</pre>
</div>
</div>
I like the idea of this approach for a couple of reasons.
You can new up a Client or a Phone in you controller and know for a fact that or expected model properties are there when Angular tries to render them. (This avoids the annoying client.phones.phoneId is not defined errors)
Your model definition is now in one spot on the JS side of the house. Even though this looks like duplication ... well it is, but you will have to define this somewhere to send it back to the server anyways. So I prefer to do it in one reusable spot.
You get and Arrays of Client and Phone when you are outputting the model properties to the Console. This just make me feel good :-)
This was a bit of an overkill for your question, but I like the clean feel of this approach to Front End Modeling.
You can create a new object for your model and add the phones property there.
View
<div class="form-group col-lg-4">
<label>Home Phone</label>
<input class="form-control" ng-model="homePhone">
</div>
<div class="form-group col-lg-4">
<label>Cellphone</label>
<input class="form-control" ng-model="cellPhone">
</div>
<div class="form-group col-lg-4">
<label>Contact Phone</label>
<input class="form-control" ng-model="contactPhone">
</div>
<button class="btn btn-primary" style="float: right" ng-click="saveClient()">Confirmar</button>
Controller
$scope.saveClient = function() {
var phones = [
{ClientId: $scope.client.Id, PhoneType: 1, Number: $scope.homePhone},
{ClientId: $scope.client.Id, PhoneType: 2, Number: $scope.cellPhone},
{ClientId: $scope.client.Id, PhoneType: 3, Number: $scope.contactPhone}
]; // Not sure about the PhoneTypes. There are multiple ways to implement this, I'll leave it up to you.
var data = {
Id: $scope.client.Id,
Name: $scope.client.Name,
Email: $scope.client.Email,
Phones: phones
};
clientesAPI.saveCliente(data).success(function() {
alert('OK');
}).error(function () {
alert('Error');
});
};
first you need to define ng-model for your view, suppose -
<input class="form-control" ng-model="hPhone">
<input class="form-control" ng-model="cellPhone">
<input class="form-control" ng-model="contactPhone">
Now you can make a json object and post that, then on server side you can access all the phones by for-each loop -inside your controller -
var vm = this;
var phnList = {
hphone: vm.hphone,
cellPhone: vm.cellPhone,
contactPhn: vm.contactPhone
};
Now u can post using $http service
$(http).({
url : "urULR",
data : phnList,
method :"post"
}).then(fuction(response) {
vm.message = "save success";
});
Related
My input binds to object line.product however typeahead is returning the list of pairs of products and supplier. The current ps.product as ps.product.code for ps in getProductSupplierRefList($viewValue) does not return the expected product.
<input ng-model="line.product"
class=" form-control"
typeahead="ps.product as ps.product.code for ps in getProductSupplierRefList($viewValue)"
typeahead-loading="isLoading"
typeahead-on-select="productSupplierSelected($item, line)"
typeahead-template-url="productSupplierRefList.html"/>
getProductSupplierRefList calls webapi and return a list of ProductSupplierRefModel:
public class ProductSupplierRefModel
{
public ProductRefModel Product { get; set; }
public SupplierRefModel Supplier { get; set; }
}
The product code is expected in text control:
Any suggestion pls?
use typeahead-input-formatter to show the code. looks like ps.product as ps.product.code is not working???
<input ng-model="line.product"
type="text"
class=" form-control"
ng-keyup="getProductSupplierRefList($event)"
typeahead="ps.product as ps.product.code for ps in filterProductSuppliers"
typeahead-loading="isLoading"
typeahead-input-formatter="formatProduct($model)"
typeahead-wait-ms=500
typeahead-on-select="productSupplierSelected($item, line)"
typeahead-template-url="productSupplierRefList.html" />
where the formatter is:
$scope.formatProduct=function(model) {
return model ? model.code : '';
}
the product code now appears as expected:
Don't use function in typehead. Also be careful about the model properties camel case.
<input ng-model="line.product"
class=" form-control"
ng-keyup="getProductSupplierRefList($event)"
typeahead="ps.Product as ps.Product.Code for ps in productOptions"
typeahead-loading="isLoading"
typeahead-on-select="productSupplierSelected($item, line)"
typeahead-template-url="productSupplierRefList.html"/>
$scope.productOptions = [];
$scope.getProductSupplierRefList = function(evt){
var value = angular.element(evt.target).val();
$http.get('url/' + value).then(funtion(response){
$scope.productOptions = response.data;
})
}
//test ps.Product.Code with _tojson(ps.Product.Code)
$scope._tojson= function(obj){
return angular.toJson(obj);
}
There is a multi select element in my page.
<div class="form-group">
<select ng-show="'#Model.IsWinnerFilterVisible'" class="selectpicker" multiple title="Kazanan" ng-model="MainWinnerFilterSelected" id="ddl_winnerid"
data-ng-options="MainWinnerFilter.Id as MainWinnerFilter.Name for MainWinnerFilter in MainWinnerFilters"></select>
</div>
<div class="form-group">
<select ng-show="'#Model.IsReasonFilterVisible'" class="form-control" title="İlgilenilmeme Nedeni" ng-model="MainReasonFilterSelected" id="ddl_reasonid" ng-init="MainReasonFilterSelected= #Model.SelectedReason"
data-ng-options="MainReasonFilter.Id as MainReasonFilter.Name for MainReasonFilter in MainReasonFilters">
<option value="">İlgilenilmeme Nedeni</option>
</select>
</div>
And i can load this first with the code below
$scope.MainWinnerFilterSelected = #Html.Raw(Json.Encode(Model.SelectedWinner));
I want to reload this element with a new data but it dosent work.
$scope.loadReasonAndWinner= function() {
var productGroupFilters=$scope.productGroupFilterSelected;
var res = $http.post('#Url.Action("GetWinnerAndReasonList", "Details")', {'selectedProductGroup':productGroupFilters});
res.success(function(data, status) {
$scope.MainWinnerFilters=data.WinnerList;
$scope.MainReasonFilters=data.NotInterestingReasonList;
});
res.error(function(data, status) {
$scope.addError("alert-danger","Bir Hata oluştu.","Error");
});
}
In controller;
[HttpPost]
public ActionResult GetWinnerAndReasonList(int SelectedProductGroup)
{
var detail = new DetailsModel();
detail.SelectedProductGroup = SelectedProductGroup;
var winnerList = BiddingService.RetrieveWinners(null, VariableHelper.ListOf(detail.SelectedProductGroup));
detail.WinnerList = BiddingService.TranslateToFilter(winnerList);
var notInterestedActionStatus = new List<int>() { VariableHelper.Int(ActionStates.NotInterested) };
var notInterestingReasonList = BiddingService.RetrieveActionReason(notInterestedActionStatus, VariableHelper.ListOf(detail.SelectedProductGroup));
detail.NotInterestingReasonList = BiddingService.TranslateToFilter(notInterestingReasonList);
return Json(detail);
}
New data comes true and it works with combobox (MainReasonFilter) but it dosent change the items in multiselect element(MainWinnerFilter). Any idea with that?
I am stuck saving multiple rows I pushed in "$scope.arr" to my SQL Server database. I have my code below and it works fine but when I click on "Save To DB" button after adding/pushing some entries by pressing "Add Person" button, it passes a row with null values to SQL Server database. Please guide me where I am doing the mistake:
I also heard about using angular.forEach loop but I am confused using that too.
I have my model class "TestModel.cs" here:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TestProj.Models
{
public class TestModel
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
My MVC Controller named TestController's Add method here:
[HttpPost]
public string AddPerson(TestModel test)
using (TestContext db = new TestContext())
{
if (test != null)
{
db.TestModels.Add(test);
db.SaveChanges();
return "Successful";
}
else
{
return "Failed";
}
}
}
My AngularJS script here:
var app = angular.module("TestApp", []);
app.controller("TestCtrl", function ($scope, TestService) {
$scope.arr = [];
$scope.addPerson = function () {
var myobj = {
FirstName: $scope.firstname,
LastName: $scope.lastname
}
$scope.arr.push(myobj);
};
$scope.savePerson = function () {
var TestData = TestService.AddPer($scope.arr);
TestData.then(function (msg) {
alert(msg.data);
}, function () {
alert('Error In Adding Person');
});
};
});
app.service("TestService", function ($http) {
this.AddPer = function (person) {
var response = $http({
method: "post",
url: "/Test/AddPerson",
data: JSON.stringify(person),
dataType: "json",
});
console.log(response);
return response;
}
});
And my Index.cshtml file here:
<div ng-controller="TestCtrl">
<form>
FirstName: <input class="form-control" ng-model="firstname" /><br />
LastName: <input class="form-control" ng-model="lastname" /><br />
<button class="btn btn-success" ng-click="addPerson()">Add Person</button>
<button class="btn btn-success" ng-click="savePerson()">Save To DB</button>
<table class="table table-bordered">
<tr>
<th>S. No</th>
<th>First Name</th>
<th>Last Name</th>
</tr>
<tr ng-repeat="a in arr">
<td>{{$index+1}}</td>
<td>{{a.FirstName}}</td>
<td>{{a.LastName}}</td>
</tr>
</table>
</form>
</div>
<script src="~/Scripts/MyAngular/Module.js"></script>
Your help will be appreciated. Thanks!
Then server side action should expect collection of TestModel, you could us List there. If you [FromBody] before parameter, you don't need to stringify data before posting it to server.
Code
[HttpPost]
public string AddPerson([FromBody] List<TestModel> test)
using(TestContext db = new TestContext()) {
test.forEach(t=> {
if (t != null) {
db.TestModels.Add(t);
return "Successful";
} else {
return "Failed";
}
});
db.SaveChanges(); //save context at the end, when no error occurs
}
}
The problem was in my Server Side Code i.e, my C# controller, this method worked:
[HttpPost]
public void AddPerson(List<TestModel> test)
{
using (TestContext db = new TestContext())
{
foreach(var t in test)
{
if (t != null)
{
db.TestModels.Add(t);
Console.WriteLine("Success");
}
}
db.SaveChanges(); //save context at the end, when no error occurs
}
}
I have a Web API where my repository class is:
public class myRepository
{
public myClasses.Type[] GetAllTypes()
{
return new myClasses.Type[]
{
new myClasses.Type
{
typeId="1",
typeVal = "New"
},
new myClasses.Type
{
typeId="2",
typeVal = "Old"
}
};
}
public myClasses.Employee[] GetAllEmployees()
{
return new myClasses.Employee[]
{
new myClasses.Employee
{
empId="111111",
empFName = "Jane",
empLName="Doe"
},
new myClasses.Employee
{
empId="222222",
empFName = "John",
empLName="Doe"
}
};
}
public bool VerifyEmployeeId(string id)
{
myClasses.Employee[] emp = new myClasses.Employee[]
{
new myClasses.Employee
{
empId="111111",
empFName = "Jane",
empLName="Doe"
},
new myClasses.Employee
{
empId="222222",
empFName = "John",
empLName="Doe"
}
};
for (var i = 0; i <= emp.Length - 1; i++)
{
if (emp[i].empId == id)
return true;
}
return false;
}
}
and here is my controller:
public class myClassesController : ApiController
{
private myRepository empRepository;
public myClassesController()
{
this.empRepository = new myRepository();
}
public myClasses.Type[] GetTypes()
{
return empRepository.GetAllTypes();
}
public myClasses.Employee[] GetEmployees()
{
return empRepository.GetAllEmployees();
}
[HttpGet]
public bool VerifyEmployee(string id)
{
return empRepository.VerifyEmployeeId(string id);
}
}
Now I have created a web application where I included angularJS. Here is my html (EmployeeLogin.html)
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Employee ID</title>
<script src="../../Scripts/jquery-2.2.0.min.js"></script>
<script src="../../Scripts/angular-ui/ui-bootstrap.min.js"></script>
<script src="../../Scripts/angular.js"></script>
<script src="EmployeeLoginCtrl.js"></script>
</head>
<body ng-app="myClassesApp">
<div ng-controller="myClassesController">
<form ng-submit="ValidateEmployeeId()" method="get" id="frmLogin" action="">
<input ng-model="empId" type="text" id="txtEmpId" />
<br />
<input type="submit" value="Submit" id="btnSubmit" />
<br />
<span id="lblMsg">{{EmployeeValidate}}</span>
</form>
</div>
</body>
</html>
What I want to accomplish is when the user enters their ID, I want to call myController function VerifyEmployee, pass it the ID entered by the user and output message of success or failure to the web page.
I am in need of some assistance fixing up my angular controller. here is what I got so far:
(function () {
angular.module("myClassesApp", []).controller("myClassesController", myValidateFunction);
myValidateFunction.$inject("$scope", "$http");
function myValidateFunction($scope, $http) {
$scope.ValidateEmployeeId = function () {
alert($scope.empId);
$http.get('http://localhost:49358/api/myClasses/VerifyEmployee/' + $scope.empId).
then(function (result) {
alert(result);
$scope.EmployeeValidate = result.data;
});
}
};
})();
My main question is how do I pass the id from the textbox to the angular controller?
Also how I ensure my angular function is only called when the form is submitted by the user, not when the page loads initially?
Can someone please point me in the right direction in regards to getting data from Web API and displaying it on the page?
So far the page loads, immediately displays "false" in the message label. then I enter ID and click submit and then nothing happens. ow can I ensure that angular function gets called?
So, in your UI, whatever you're data-binding to (ng-model, etc..) you have access to in Angular. In your example, you have <input ng-model="empId" type="text" id="txtEmpId" /> but I don't see a $scope.empId..Where is empId coming from then?
UI
<div ng-app ng-controller="myClassesController">
<div>Enter your User ID:</div>
<input ng-model="empId"></input>
<input type="submit" ng-click="checkUser()" value="Login"></input>
</div>
Controller
function myClassesController($scope) {
$scope.empId = '';
$scope.checkUser = function () {
// hit your api with user id
alert($scope.empId);
}
}
Here's a working example for you : JSFiddle
I am looking for a VERY simple example that shows wiring up Knockback code to a backbone model that connects via RESTful service. I am using ServiceStack|c# backend. All of the links below are too complicated and use localStore rather than a RESTful service via url. I also prefer to see examples in Javascript not CoffeeScript.
My example url is something like localhost/entities where hitting this will cause the RESTful webservice to return all of the entities. Hitting it with localhost/entity/1 would return the entity with an Id of 1.
_http://kmalakoff.github.com/knockback/index.html
_https://github.com/kmalakoff/knockback-reference-app/
_https://github.com/addyosmani/todomvc
The following is the example from knockback tutorial on the first link:
Models, Collection, ViewModel, and Bindings:
// Generated by CoffeeScript 1.3.3
var model, view_model;
model = new Backbone.Model({
first_name: "Planet",
last_name: "Earth"
});
view_model = kb.viewModel(model);
view_model.full_name = ko.computed((function() {
return "" + (this.first_name()) + " " + (this.last_name());
}), view_model);
ko.applyBindings(view_model, $('#kb_view_model_computed')[0]);
But there is no mention of how you would wire the backbone model up to your RESTful webservice.
There are examples of how do this via Backbone but I am uncertain as to how things change when using Knockback.
The following links were found, but not helpful:
_http://stackoverflow.com/questions/7992431/using-knockoutjs-backbone-together
_http://stackoverflow.com/questions/9704220/is-knockback-js-production-ready
_http://stackoverflow.com/questions/10434203/defining-models-on-server-side-when-using-mvvm-with-knockout-js
Thanks in advance for any assistance provided. Btw you don't want hyperlinks you get underscores... ;)
With much help and support from Kevin Malakoff from the great Knockback project I was able to get a small example working! I used the ServiceStack Backbone Todos project as a starting point.
c# file: Global.asax.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using ServiceStack.Redis;
using ServiceStack.ServiceInterface;
using ServiceStack.WebHost.Endpoints;
namespace MyApp
{
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class PersonService : RestServiceBase<Person>
{
public static Person kevin = new Person { Id = 1, FirstName = "Kevin", LastName = "Malakoff" };
public static Person scott = new Person { Id = 2, FirstName = "Scott", LastName = "Idler" };
public static List<Person> people = new List<Person> { kevin, scott };
public override object OnGet(Person person)
{
if (person.Id != default(int))
return people[person.Id-1];
return people;
}
public override object OnPost(Person person)
{
return base.OnPost(person);
}
public override object OnPut(Person person)
{
return OnPost(person);
}
public override object OnDelete(Person person)
{
return base.OnDelete(person);
}
}
public class AppHost : AppHostBase
{
public AppHost() : base("MyApp", typeof(PersonService).Assembly) { }
public override void Configure(Funq.Container container)
{
ServiceStack.Text.JsConfig.EmitCamelCaseNames = true;
Routes
.Add<Person>("/persons")
.Add<Person>("/persons/{Id}");
}
}
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
new AppHost().Init();
}
}
}
html file: default.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>MyApp2</title>
<script>window.JSON || document.write('<script src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js">\x3C/script>')</script>
<script src="Scripts/jquery-1.8.0.js" type="text/javascript" ></script>
<script src="Scripts/knockback-full-stack-0.16.1.js" type="text/javascript" ></script>
<script src="myapp.js" type="text/javascript" ></script>
</head>
<body>
<div id="myapp">
<div class="title">
<h1>MyApp</h1>
</div>
<div class="content">
<div id='kb_observable'>
<p>First name: <input class='text' data-bind="value: firstName" /></p>
<p>Last name: <input class='input-small pull-right' data-bind="value: lastName" /></p>
<p>Hello, <span data-bind="text: fullName"></span>!</p>
</div>
<div id="kb_collection_observable">
<div data-bind="if: persons">
<span>Has Persons</span>
</div>
<div data-bind="foreach: persons">
<p>First name: <input class='text' data-bind="value: firstName" /></p>
<p>Last name: <input class='input-small pull-right' data-bind="value: lastName" /></p>
</div>
</div>
</div>
</div>
</body>
</html>
javascript file: myapp.js
$(function() {
//model
var PersonModel = Backbone.Model.extend({ urlRoot: '/MyApp/persons' });
var model = new PersonModel({ id: 1 });
model.fetch();
//viewmodel
var PersonViewModel = function (person) {
this.firstName = kb.observable(person, 'firstName');
this.lastName = kb.observable(person, 'lastName');
this.fullName = ko.computed((function () {
return "" + (this.firstName()) + " " + (this.lastName());
}), this);
};
var personViewModel = new PersonViewModel(model);
//binding
ko.applyBindings(personViewModel, $('#kb_observable')[0]);
//model
var PersonsModel = Backbone.Collection.extend({ model: PersonModel, url: '/MyApp/persons' });
var personsModel = new PersonsModel();
personsModel.fetch();
//viewmodel
var PersonsViewModel = function (persons) {
this.persons = kb.collectionObservable(persons)
};
var personsViewModel = new PersonsViewModel(personsModel);
//binding
ko.applyBindings(personsViewModel, $('#kb_collection_observable')[0]); });
I put together a very simple example. It assumes you already know how to use backbone and knockout so this just gives a quick example of how they can be used together
http://coder2.blogspot.com/2013/02/backbonejs-and-knockoutjs.html