How to pass a List to javascript in JSF - javascript

I am struggling with a JSF project.
In my service, I retrieve a List of custom object (here Sales), and I have to pass it to my jsf view, specifically into the javascript, to make graphs.
My problem is, I don't understand how to send the data from the controller (my managed beans) to my view, and which tag to use in my view to retrieve it in my javascript.
I think I can pass my data like this, but I'm not sure
public String passData() {
List<Sales> bestSelling = saleService.getBestSellingProduct(null, null, null, null);
List<Sales> worstSelling = saleService.getWorstSellingProduct(null, null, null, null);
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("bestSelling", bestSelling);
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("worstSelling", worstSelling);
return "./all.jsf?faces-redirect=true";
}

You need to create a JSON object that you'll assign to a JavaScript variable. To create JSON you may find useful to incorporate a library like Gson.
So, it'll look like:
var sales = #{bean.jsonList};
with Bean#getJsonList as:
public String getJsonList() {
return (sales == null) ? "" : new Gson.toJson(sales);
}
Just don't forget that the script with such assignment must be handled by the FacesServlet.

Related

Laravel - Modifying data for API only for convenience

Let's assume the following data that is exactly being returned like it's stored into database:
[
{
"user_name": "User 1",
"photo_file": "user1.jpg"
},
{
"user_name": "User 2",
"photo_file": "user2.jpg"
}
// ...
]
I want to use this data in a JavaScript application but I'd like to append a full path of the user's photo, like doing a treatment for the data before returning it to the API. How can I do that using Laravel?
I assume at present you're just converting the results of your query into JSON and returning that. This works, but it does mean the response is tightly coupled to your database structure, which is a bad idea. Ideally you should have a layer of abstraction to handle adding and formatting data, kind of like a view layer in MVC.
There are plenty of solutions for this. I use Fractal for my Laravel API's. It allows you to easily customise the output of a particular endpoint by specifying a transformer that will render that object for you. That way you can easily choose the data to display and format it how you wish.
Accessors are good for this.
Let's assume your data is stored in a model called Customer. I would write an accessor like this:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Customer extends Model
{
protected $appends = ['photo_file']; // In order to see the new attribute in json dumps
public function getPhotoPathAttribute()
{
$name = $this->getAttribute('photo_file');
if(!isset($name))
return null;
return '/full/path/to/image/' . $name;
}
}
This way you can now call $customer->photo_path and it will return `/full/path/to/image/image_name.jpg' (or null if the attribute is not set).
Edit:
In order to show this attribute in jsons (without specifically calling $model->photo_path) you will also need to add protected $appends = ['photo_file'] to the model (updated).
I would recommend against overriding original name (so I leave photo_file attribute untouched).
If you are building Laravel API, sure, as Matthew said, go and check Fractal. But don't forget to Dingo, the best tool for building API at Laravel. And it uses Fractal too.

how to pass complicated data between mvc and javascript

I'm trying to build a UI with two dropdowns. The first one is "category", the second one is "sub-category". I can build a static list of "category" in my razor view. I want the "sub-category" item list to be dynamically updated when "category" is changed. I'm trying to pass all category information from server side to client side since the list is not big and there is no security issue. But I cannot find a good way to format my data and transfer it to client side. I can generate a json object with all of my category trees using the following code:
ExpandoObject catToSubcatMap = new ExpandoObject();
foreach (var cat in repository.Categories)
{
var subcats = repository.SubCategories.Where(s => s.ParentID == cat.CategoryID);
List<Object> subcatNameList = new List<object>();
foreach(var subcat in subcats)
{
subcatNameList.Add(new { Name = subcat.Name });
}
AddProperty(catToSubcatMap, cat.Name, subcatNameList);
}
Session["CatToSubcatMap"] = JsonConvert.SerializeObject(catToSubcatMap, Newtonsoft.Json.Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
The json itself looks perfect. But when I tried to read the value from my jQuery function, it failed:
var sss = '#Session["CatToSubcatMap"]';
It seems like there are too many special characters in the json string. My generic question is: how should I format and pass complicated data between server and client. Using Viewbag or Session, which one is preferred?
Thanks
Chris
You can do what you are trying to do; what you have should be formatted correctly, but you just have to include Html.Raw.
var sss = #(
Html.Raw(Session["CatToSubcatMap"].ToString())
);
Raw will essentially write out directly to the response without encoding the contents, which is what likely was happening.

Ready ViewBag values from controller?

In my controller I have the following ViewBag which has hard coded values for a drop down list
public ActionResult Order(string id, string printRequest)
{
this.ViewBag.PartialReasons = new List<string>() {" ", "Insufficient stock", "Suspended", "Retired", "Ordered Incorrectly", "Unable to deliver" };
}
I want to do is that once from a drop down the value "Unable to deliver" is selected, then have a alert POP up with "HELLO EVERYONE" appear, then user should be able to click on and save, my existing save function onclick is below,
in a nutshell just want to read a value from a controller viewbag.
$('.pcss-save').click(function() {
if (CheckSerialNumbersForQuantity()) {
if (CheckReasons()) { //If Ordered incrrectly
$('#genericmodal').find(".pcss-submit-genericmodal").unbind("click");
$('#genericmodal').find(".modal-title").html("Confirmation");
$('#genericmodal').find(".modal-body").html("This order will be Cancelled");
$('#genericmodal').modal('show');
$('#genericmodal').find(".pcss-submit-genericmodal").click(function() {
$("#orderform").submit();
});
} else {
$("#orderform").submit();
}
}
});
First some questions:
How are you loading the Viewbag values into the drop-down?
Are you using Razor views?
it seems you are asking multiple questions, so I'm going to try and hit each.
Typically drop downs are key-value pairs. With Razor views you can use:
#Html.DropDownList("reasonListID", new SelectList(ViewBag.PartialReasons, "reasonCode", "reasonName"))
This assumes that the viewbag object is a list of object with two properties reasonCode and reasonName.
Pure lists of strings are not really used to drive logic, you want to codify your potential values to give yourself clear and easy comparisons. In this way, you can simply look at reasonCode and not have to code for comparing your select value to "Some long string that may not have a lot of meaning in code" e.g. this would probably be in your CheckReasons() function.
if CheckReasons() == "UD") {
showModal( "HELLO EVERYONE");
}
is easier than
if CheckReasons() == "Unable to deliver") {
showModal("HELLO EVERYONE");
}
As far as popping the modal, it looks like you are using jquery, so take a look that this answered question: MVC3 Razor and Modal popup
In your view, you should be able to call your ViewBag directly by using #ViewBag.PartialReasons and when the Razor engine renders the script, it will use those values in #ViewBag.PartialReasons.
You might want to do something like this.
$('#yourDropDownID').on('change', function(){
if(CheckReasons()){
var genericModal = $('#genericmodal'); //Avoids rescanning the dom.
genericModal.find(".pcss-submit-genericmodal").unbind("click");
genericModal.find(".modal-title").html("Confirmation");
genericModal.find(".modal-body").html("This order will be Cancelled");
genericModal.modal('show');
genericModal.find(".pcss-submit-genericmodal").click(function() {
$("#orderform").submit();
}
});
And your check reasons might be something like this. This is kind of open to interpretation.
function CheckReasons(){
var myReason = #String.Join(ViewBag.PartialReasons.ToArray());
//loop and figure it out if your reason is selected and return true or false
}
This was all written off the top of my head, so it may need a little tweaking, but this should get you started with what you're looking to do.
UPDATE
You cannot access the ViewBag within your browser as it only exists server side. You need to render out a script that accomplishes what you desire on the server using ViewBag. The Razor engine will fill in the output from the C# code.

Loading Breeze Navigation Properties offline

I am using the latest versions of Angular, breeze, EF.
I am constructing a complex object on a client called a Quote which is added to a job. This has a QuoteMeasure added to it. One of the properties of QuoteMeasure is a navigation property called measure:
var quote = em.createEntity("Quote", { id: breeze.core.getUuid() }),
quoteMeasure,
measure;
measure = _getMeasureFromLookups(4);
quoteMeasure = em.createEntity("QuoteMeasure", { id: breeze.core.getUuid(), quoteId: quote.id });
I have tried the following which executes a query to the server
quoteMeasure.measureId = measure.id;
quoteMeasure.entityAspect.loadNavigationProperty("measure").then(function () {
console.log(quoteMeasure.measure);
});
quote.quoteMeasures.push(quoteMeasure);
job.quotes.push(quote);
to url /Breeze/Data/Measure?$filter=Id%20eq%204&
which does not exist. I would ideally like to set the navigation property manually as it is static data and previously obtained from a breeze query lookups on the server:
[HttpGet]
public object Lookups()
{
var measures = UnitOfWork.MeasureRepository.Get(null, q => q.OrderBy(m => m.Ordinal)).ToList();
return new { measures = measures };
}
This is what the function _getMeasureFromLookups does, it looks up the previously stored measure. I would like to do assign it this way:
quoteMeasure.measure = measure;
But I get the following meaningless error on the client:
Error: A is undefined M#//llhst/X/Scripts/breeze.min.js:1 d/f.set#//llhst/X/Scripts/breeze.min.js:5 _createNewQuote#//llhst/X/Scripts/app/services/jobService.js:76
This I assume is because a full tree of objects has been downloaded via the lookup rather than an individual measure entity. In http://www.breezejs.com/documentation/navigation-properties there is a section on 'Omitting navigation properties' but then it neglects to tell you how to do this.
So my question is what is best practise for loading navigation property data offline? How can I modify the sample above so that it works?
If I understand your requirement correctly, you should be able to construct your quote and quoteMeasure entities as follows:
var quote = em.createEntity("Quote", { id: breeze.core.getUuid() });
//the assignment quoteId: quote.id is the same as quote.quoteMeasures.push(quoteMeasure)
//you don't need to add it again to the collection
var quoteMeasure = em.createEntity("QuoteMeasure", { id: breeze.core.getUuid(), quoteId: quote.id });
var measure = _getMeasureFromLookups(4);
quoteMeasure.measure = measure;
//or
//quoteMeasure.measureId = measure.id
//your _getMeasureFromLookups should look something like this
function _getMeasureFromLookups(measureId) {
//getEntityByKey will look up Measure from client cache
return em.getEntityByKey('Measure', measureId);
}
Calling loadNavigationProperty will initiate a query to the server.
The 'Omitting navigation properties' section actually tells you how you can omit the principal side of the association. So for example, to apply it to your EF model, if you don't want a Quote to be able to navigate to all QuoteMeasures, you can do the following:
//EF Model on Server
public class Quote {
//Simply remove or comment this collection navigation property
//public virtual ICollection<QuoteMeasure> QuoteMeasures { get; set; }
}
Hope this helps.
Seems the problem was the ommission of these statements:
Configuration.ProxyCreationEnabled = false;
Configuration.LazyLoadingEnabled = false;
Not having this caused the preloading of not only the navigation properties but all of theirs as well which caused the obscure error I noted above. No other modifications were required to get the code working.
EntityAspect.loadNavigationProperty() always makes a request to the server. If you want properties be loaded without making a separate request, do Eager loading with EF.
If you have several properties which are null when breeze fetches them, and you don't want to make several loadNavigationProperty calls, use EntityQuery.expand() method. You can list any properties you need to be loaded

Couchbase Java API and javascript view not returning value for a specific Key

I am using couchbase API in java
View view = client.getView("dev_1", "view1");
Query query = new Query();
query.setIncludeDocs(true);
query.setKey(this.Key);
ViewResponse res=client.query(view, query);
for(ViewRow row: res)
{
// Print out some infos about the document
a=a+" "+row.getKey()+" : "+row.getValue()+"<br/>";
}
return a;
and the java script view in couchbase
function (doc,meta) {
emit(meta.id,doc);
}
So, when I remove the statement query.setkey(this.Key) it works returns me all the tables, what am I missing here .. How can I change the function to refect only the table name mentioned in the key
Change the map function like this:
function (doc,meta) {
emit(doc.table,null);
}
it is good practice not to emit the entire document like:
emit(doc.table, doc)
NB: This is surprisingly important:
i have tried using setKey("key") so many times from Java projects and setting the key using CouchBase Console 3.0.1's Filter Result dialog, but nothing get returned.
One day, i used setInclusiveEnd and it worked. i checked the setInclusiveEnd checkbox in CouchBase Console 3.0.1's Filter Result dialog and i got json output.
query.setKey("whatEverKey");
query.setInclusiveEnd(true);
i hope this will be helpful to others having the same issue. if anyone finds another way out, please feel free to add a comment about it.
i don't know why their documentation does not specify this.
EXTRA
If your json is derived from an entity class in a Java Project, make sure to include an if statement to test the json field for the entity class name to enclose you emit statement. This will avoid the key being emitted as null:
if(doc._class == "path.to.Entity") {
emit(doc.table, null);
}

Categories

Resources