Retrieving Data From Controller Based On ListBox Value - angularjs

I have a form with about 20 fields. I have a ListBox that is populated with Customers from the Model when the page loads. Once the user picks one of those Customers from the ListBox, I want to post to the Controller the selected Customer, get customer's info, return it to same view, and populate some of the fields with the Customer's info.
Here is what I am trying now, but it might not be the best way. Also, the onclick gets called on page load, which causes an infinite loop.
View - CreateUser
#Html.ListBoxFor(x => x.Id,
Model.Customers.Select(
x => (new SelectListItem {
Text = x.Name,
Value = x.Value.ToString(),
Selected = x.IsSelected})).OrderBy(x => x.Text),
htmlAttributes new {
onclick = #Html.Action("GetCustomerInfo", "Customer", Model)
})
Controller - Customer
[ChildActionOnly]
public ActionResult GetCustomerInfo(CustomerModel Model)
{
// populate model with customer info
return View("CreateUser", Model);
}
Also, if there is a better way for this solution, I would love to hear any ideas. I am trying to avoid loading all Customers and then just using Angular to change the text fields based on selected Customer, since there is going to be over 1,000 customers and it would be slow to initially load all of them.

#Html.Action() is razor code and is parsed on the server so GetCustomerInfo() is called before the page is sent to the client. The fact its associated with the onclick event of a control is irrelevant. The infinite loop is because the view returned by GetCustomerInfo is the same view your trying to render - it contains the same #Html.Action() so GetCustomerInfo is called again, which returns a view with the same #Html.Action() so GetCustomerInfo is called again and so on.
You can use ajax to update the DOM with the selected customers details.
View models
public class SelectCustomerVM
{
[Display(Name="Select customer to display details")]
public int? CustomerID { get; set; }
public SelectList CustomerList { get; set; }
}
public class CustomerVM
{
public int ID { get; set; }
public string Name { get; set; }
// other properties of customer
}
Controller
public ActionResult Index()
{
SelectCustomerVM model = new SelectCustomerVM();
model.CustomerList = new SelectList(db.Customers, "ID", "Name");
return View(model);
}
public ActionResult Details(int ID)
{
CustomerVM model = new CustomerVM();
// get customer from database and map properties to CustomerVM
return PartialView(model);
}
Index.cshtml
#model SelectCustomerVM
#Html.LabelFor(m => m.CustomerID)
#Html.DropDownListFor(m => m.CustomerID, Model.CustomerList, "--Please select--")
<div id=customerdetails></div>
<script type="text/javascript">
$('#CustomerID').change(function() {
var customerID = $(this).val();
if(customerID) {
$.get('#Url.Action("Details", "Customer")', { ID: customerID }, function(data) {
$('#customerdetails').html(data);
});
} else {
$('#customerdetails').empty();
}
});
</script>
GetCustomer.cshtml (partial view)
#model CustomerVM
#DisplayFor(m => m.ID)
#DisplayFor(m => m.Name)
....
Some best practices to note. Don't pollute your view with code to construct SelectList's - that's the responsibility of the controller; and use Unobtrusive javascript - don't mix content and behavior.

Related

How to sort SourceCache, bind to BindingList, and handle IChangeSets manually with Winforms?

I'm using ReactiveUI 9.21 and DynamicData 6.13 together with WinForms.
I did read https://dynamic-data.org/tag/dynamicdata/ and some other resources, but am still confused with IObservableCache, ReadOnlyObservableCollection and others when dealing with changes in DynamicData collections.
If I have a SourceCache<Result, string> recoResults in a model class - how can I sort it there, and then:
Q1: How do I expose SourceCache to be bound to a BindingList<Result> (in a view model for a view with a DataGridView)?
Q2: At the same time, how do I expose SourceCache to be able to react to IChangeSets manually (in a view with a non-reactive plot component)?
What I have:
In the moment, I expose the SourceCache unsorted as IObservableCache in the model and connect to it the views/view models:
public IObservableCache<Result, string> RecoResults { get; protected set; }
private readonly SourceCache<Result, string> recoResults;
public DropModel()
{
recoResults = new SourceCache<Result, string>(e => e.ID);
RecoResults = recoResults.AsObservableCache();
}
Sorting for the DataGridView's BindingList works in the view model:
ResultBindingList = new BindingList<RecoResult>();
DropModel.RecoResults.Connect()
.Sort(recoResultComparer)
.ObserveOn(RxApp.MainThreadScheduler)
.Bind(ResultBindingList)
.Subscribe();
But I don't know how to do the sorting in the view with the non-reactive plot component:
// Still unsorted results:
var observableResults = VM.DropModel.RecoResults.Connect();
// Add result:
var d2 = observableResults.WhereReasonsAre(ChangeReason.Add)
.ObserveOn(RxApp.MainThreadScheduler)
.ForEachChange(x => {
// Add to plot
})
.Subscribe();
// Remove result:
var d3 = observableResults.WhereReasonsAre(ChangeReason.Remove)
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(_ => {
// Remove from plot
});
What I'd like to have:
I'd like to do the sorting in a central place, because the user can choose between two ways of sorting and I want to sync it in all views. I'd like to expose the sorted results as a single property and use it for the BindingList as well as for manual change iterations.
In the model, I already tried:
public ??? SortedResults { get; protected set; }
recoResults.Connect()
.Sort(recoResultComparer)
.ObserveOn(RxApp.MainThreadScheduler)
.Bind(SortedResults)
.Subscribe();
Q3: What return type is the best to use for SortedResults?
And in general:
Q4: When do we use IObservableCache/IObservableList, and when do we use ReadOnlyObservableCollection? And when is IObservable<IChangeSet<T, key>> used?

using controller functions to display multiple pages

Lets say i have multiple public functions in a single controller, i am trying to fine a way to display 1 option per page for example, first page user selects a schoolYear then hit submit, next page the user selects a school and hit submit, 3rd page the user selects a term and with a final page of all the selected fields being shown and a delete button. i am starting to test my page now and am wondering what is the best way to accomplish this?
class SchoolYearsController extends AppController
{
public function index()
{
}
public function chooseYear()
{
$schoolYearsTable = $this->loadModel('SchoolYears');
$schoolYears = $schoolYearsTable->find()->order(['SchoolYears.endYear'=>'desc']);
$this->set('schoolYears',$schoolYears);
$this->request->getSession()->write('App.schoolYear',$this->request->getData('schoolYear'));
return $this->redirect(['controller'=>'SchoolYears', 'action'=>'chooseSchool']);
}
public function chooseSchool()
{
$schoolListsTable = $this->loadModel('Schools');
$schoolYear = $this->session->read('App.schoolYear');
$schools = $schoolListsTable->find()
->where([
'fiscalYear' => $schoolYear,
'districtCode' => 'MA',
])
;
$this->set('schools',$schools);
return $this->redirect(['controller'=>'SchoolYears', 'action'=>'chooseTerm']);
}
public function chooseTerm()
{
$chosenTerm = $this->request->getData();
}
}

Make a list field editable when this field is a many_to_one type using in Sonata-project Symfony

My entity
/**
* #ORM\ManyToOne(targetEntity="Estat", inversedBy="temes")
*/
private $estat;
public function setEstat(\Ncd\ForumBundle\Entity\Estat $estat = null)
{
$this->estat = $estat;
return $this;
}
My admin
protected function configureListFields(ListMapper $listMapper)
{
//$estats=$this->getEstatsPossibles()->toArray();
$estats=array();
foreach($this->getEstatsPossibles() as $estat)
{
$estats[$estat->getId()]=$estat->getNom();
}
$listMapper
->add('estat', 'choice',['editable' => true,'choices'=> $estats])
I'd like to make estat field editable in the list grid. Doing it on this way I get make it editable, a combobox appears but when I chose an option I get an exception because setEstat function of my entity does not recive an Estat entity, but a string (the array's key).
Trying
->add('estat', 'many_to_one',['editable' => true,'choices'=> $estats])
Only appears a link to the entity without any possibility to change.
Is it possible?
Waiting for a better and cleaner solution I'v solved this injecting an entityManager in my entity following the solution of this answer:
Get entityManager inside an Entity
Then, in my entity I've changed setEstat function:
public function setEstat( $estat = null)
{
if (is_object($estat) && get_class($estat)=='Ncd\ForumBundle\Entity\Estat')
{
$this->estat=$estat;
} else {
$estat_o=$this->em->getRepository('Ncd\ForumBundle\Entity\Estat')->find((int)$estat);
$this->estat = $estat_o;
}
return $this;
}

ReactiveUI "Compelling Example" how to refresh the search results

My question is in regards to the "Compelling Example" given for ReactiveUI where as a person types in a search bar, the search occurs asynchronously. Suppose though I wanted to provide my user with a way to refresh the current search results. I could just ask them to backspace in the search bar and retype their last character. However, they are asking for a "Refresh" button because it's not obvious to them how to refresh the current results.
I can't think of how to do this within the context of the example:
public class TheViewModel : ReactiveObject
{
private string query;
private readonly ObservableAsPropertyHelper<List<string>> matches;
public TheViewModel()
{
var searchEngine = this.ObservableForProperty(input => input.Query)
.Value()
.DistinctUntilChanged()
.Throttle(TimeSpan.FromMilliseconds(800))
.Where(query => !string.IsNullOrWhiteSpace(query) && query.Length > 1);
var search = searchEngine.SelectMany(TheSearchService.DoSearchAsync);
var latestResults =
searchEngine.CombineLatest(search, (latestQuery, latestSearch) => latestSearch.Query != latestQuery ? null : latestSearch.Matches)
.Where(result => result != null);
matches = latestResults.ToProperty(this, result => result.Matches);
}
public string Query
{
get
{
return query;
}
set
{
this.RaiseAndSetIfChanged(ref query, value);
}
}
public List<string> Matches
{
get
{
return matches.Value;
}
}
}
Does anyone have any suggestions on how I could capture a command from a button and re-execute the existing search without clearing out their current search text?
You can merge the existing observable of Query changes with a new observable that returns the current Query when the refresh button is pressed.
First a command for the refresh button:
public ReactiveCommand<Unit, String> Refresh { get; private set; }
Then you create the command and assign it, and create a merged observable of the two observables:
Refresh = ReactiveCommand.Create<Unit, String>(() => Query);
var searchEngine = Observable.Merge(
this.ObservableForProperty(input => input.Query).Value().DistinctUntilChanged(),
Refresh)
.Throttle(TimeSpan.FromMilliseconds(800))
.Where(query => !string.IsNullOrWhiteSpace(query) && query.Length > 1);
The rest can stay unchanged.

how to display first item from the model class using services and controller in angular js

I have model Class Doctor.This class is having one WebApi controller.I have Created 3 scripts namely module.js, service.js, Homecontroller.js.
The question is I want to display first item from the model class. I don't want to repeat the data, instead I want to display only one data(i.e FirstName).and also In the Next line I want to display the full name.
I have not written function for fullname.Please reply how to write function for fullname and displaying first data
// Model class : Doctor.cs
public class Doctor
{
public int Id { get; set; }
public string Reg_No { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
Web api controller for Doctor
public class DoctorsAPIController : ApiController
{
private DigitalHealthWebContext db = new DigitalHealthWebContext();
// GET: api/DoctorsAPI
public List<Doctor> GetDoctors()
{
return db.Doctors.ToList();
}
}
I have 3 scripts
Module.js
var app = angular.module("docModule", ["ngRoute"]);
Service.js
app.service('docService', function ($http) {
this.getDoctors = function () {
return $http.get("/api/DoctorsAPI");
}
})
homeController.js
app.controller('homeController', function ($scope, docService) {
getFormData();
function getFormData() {
var DoctorGet = docService.getDoctors();//The MEthod Call from service
DoctorGet.then(function (p1) { $scope.LoadDoctor = p1.data },
function (errorP1) {
$log.error('failure loading Doctor', errorP1);
});
}
});
if I use select controller with ng-Repeat I am able to get the data.
<select ng-model="Dept" class="dropdown form-control" required id="selectControl">
<option value="" disabled selected>Choose speaciality</option>
<option ng-repeat="Doctor in LoadDoctor" value="{{Doctor.Id}}">
{{Doctor.firstName}}
</option>
</select>
but If I write the following code I am not getting the data
<div class="doc-details-block" ng-controller="homeController">
<a href="#" ng-model="LoadDoctor">
<h2 class="doc-name">
{{firstName}}
</h2>
</a>
</div>
That's problem related to trying get firstName property on array with doctors.
You can try to improve it by follow script, but it will be much better to have dedicated property that store a doctor (and again better to have a dedicated service call, because it's more clear and faster)
<div class="doc-details-block" ng-controller="homeController">
<a ng-if="LoadDoctor.length > 0" href="#">
<h2 class="doc-name">
{{ LoadDpctor[0].firstName }}
</h2>
</a>
</div>

Resources