I'm using AngularJS to build an application that allows users to build reports and then submit them. The title and the time of creation are automatically generated (based on user input), and the report summary is added into a list of all of the reports the user has made.
The table will be eventually populated from a server-side JSON string (and new entries will be added to the server from the local session), but for my local testing, I need a way to add to the table during a local client-side session.
A user will go to a separate page where they can create a report: once they click "Run Report," the report summary should be added to the table, where the name of the report and the date it was created are automatically populated from the user's input. The report-creating interface is on a different page and consequentially a different controller scope from the "main" page where the list of report summaries resides.
Now, here's my question: what is the best, most Angular-tastic way to submit a report summary to the table (a.k.a. a local model) from a different controller $scope?
My code looks like this (keep in mind it is probably dreadful, and I'm planning to refactor it!):
controllers.js:
var MainCtrl = function($scope) {
$scope.reports = [
{name:'Trx Summary', date:'Mar 20, 2013 # 12:30PM'},
{name:'Trx Summary', date:'Mar 20, 2013 # 12:30PM'}
];
};
_dat_partial_view.html:
<div ng-controller="MainCtrl" class="row-fluid">
<table class="table table-striped">
...
<tr ng-repeat="report in reports">
<td>
<p>{{report.name}} <span class="label label">Generating</span></p>
</td>
<td>
<dl class="no-margin">
<dt>Date Range</dt>
<dd>Mar 3, 2013 - Mar 13, 2013</dd>
<dt>Generated</dt>
<dd>{{report.date}}</dd>
</dl>
</td>
...
</tr>
This successfully creates some dummy content that populates the table with two entries.
What do I need to do to create such a dynamic list-adder? I'm pretty sure I need to push elements into the array, but I have no idea how to do so outside of the current controller $scope. I tried placing the array's code outside of the controller $scope:
controllers.js:
reports = [
{name:'Trx Summary', date:'Mar 20, 2013 # 12:30PM'},
{name:'Trx Summary', date:'Mar 20, 2013 # 12:30PM'}
];
var MainCtrl = function($scope) {};
This simply removed the two dummy entries from the table, so that didn't work.
Any ideas?
Question 2
Another question: What is the best way to create the dynamic list of content that populates the table? The app will create the report, and store it locally. It will then try to push the new report to the server, which will generate the report and theoretically send back a result that concatenates to the JSON string. In other words, the report stays local until it is successfully sent to and generated by the server. The user cannot read the report until it is generated, but the report will also remain saved locally if the server cannot, for some reason, accept the request to generate the new report.
This said, I've seen examples that suggest using a service or factory. Is this the wisest thing to do? Is this better than a simple array like what I've got set up now?
You should be using a service here, I think the example you referenced is the correct approach
You can pass objects into a different scope by using broadcast.
controllerOne
$rootScope.$broadcast('ReportSubmit', $scope.reportObject);
data can be your object from your controller.
Then it listens for the broadcast in the other controller where you can define your data and manipulate it and have access to it..
controllerTwo
$scope.$on('ReportSubmit', function(event, data) {
$scope.reportObject = data;
};
For the second question, when you create new report, if you have the model bindings on the front-end you can do it like this.
This function you'd bind to ng-click on the create action passing in your object from the form fields.
$scope.createNewReport = function(object) {
// Assign object to var
var newReport = object;
//Add new object to data from in memory object.
$scope.reportList.push(newReport);
};
You can pass it back to the controller or server by using ajax to pass the reportList object
Found a fiddle that may potentially help you out. http://jsfiddle.net/yh3Ds/24/
Related
I am building a single page web application with Knockout that will display a variety of different information based on the user's selections. At the top there is a drop down list populated from a array of JSON objects using the options binding. Once the user makes a selection from the list how do I access the properties of the specified object in my View Model JavaScript code?
My specific app is about college football teams. The drop down list at the top has a list of team names that are pulled from an array of JSON objects that contain details about each team. This array comes from an AJAX request to the server. I know this part of my code works as I am able to use other properties in the selected object to change the look of the HTML page. However I can't figure out how to be able to access the properties of the selected object (school name, mascot, conference, etc) in my View Model Java Script so I can use those details to make further AJAX requests that will provide the user more information about the selected team (such as rosters, schedules, and stats).
There is a "value: selectedSchool" in the data-bind for my select menu in HTML that connects to a self.selectedSchool = ko.observable(); in my view model. I have tried a variety of ways to access the properties in that self.selectedSchool including dot and bracket notation, a ternary operator to check if it is null before accessing the property, and more. But as far as I can tell that variable doesn't actually contain an object that I can access, so how do I get around this?
I have tried to start small by just trying to access the 'school' property from that object and use it to get the rosters (which have the same file names as the school name) via AJAX, but eventually I want to do a lot more with it.
my HTML View:
<div>
<select data-bind="options: schools,
optionsText: function(item) {
return item.school + ' ' + item.mascot
},
value: selectedSchool,
optionsCaption: 'Choose a team...'"></select>
</div>
<div>
<!-- ko with: selectedSchool -->
<p>
School: <span data-bind="text: school"></span>
</p>
<p>
Conference: <span data-bind="text: conference"></span>
</p>
<img data-bind="attr: { src: logos[0], alt: school}">
<!-- /ko -->
</div>
The above HTML is the only part that works now. I also have a table for the team rosters with columns for things like name, position, and size once I can get the below AJAX request to work.
my JavaScript View Model:
function SchoolsViewModel() {
// Data
var self = this;
self.schools = ko.observableArray([]);
self.selectedSchool = ko.observable();
self.selectedRosterData = ko.observableArray([]);
// Behaviours
$.getJSON("/schools", function(data) {
self.schools(data);
});
//the below part works doesn't work. this is one of many tries
self.selectedRoster = function(roster) {
self.selectedSchool(roster);
$.getJSON("/rosters", { school: self.selectedSchool['school'] }, function(data) {
self.selectedRosterData(data);
});
ko.applyBindings(new SchoolsViewModel());
};
I want to make the second AJAX request return the JSON file from the server with the same name as the 'school' property from the selected JSON object in the schools array. However self.selectedSchool doesn't seem to contain a JSON object at all as far as I can tell. I don't want the AJAX request to activate until after the user selects a team from the drop down menu.
Also, for what it's worth, I eventually want to do a lot more with this than just request the roster data. The ideas is that after the user selects a team from the drop down then a list of folders will appear with several options like roster, schedule, stats, and news. When the user clicks on one of the folders they will receive the corresponding information. If I can access the properties of the selected team object from the drop-down menu then I think I can figure the rest out, but any answers with an eye on future expandability would be appreciated.
Thank you all so much for your time!
Remember selectedSchool is an observable (which, in Knockout, is technically a function), so this:
self.selectedSchool['school']
will not work. You need to "unwrap" the observable first by calling it:
self.selectedSchool()['school']
I am working on a Master-Detail app. I have a view with list control and I am binding the same with the data from an entityset called "entityset1".
Odata -> data from the entityset1
<serialno>122333</serialno>
I do have another entityset called entityset2 in the same service.
Odata -> data from the entityset2
<hdata>is Active</hdata>
Data from above entityset2 will only be retrieved with the filter (/sap/opu/odata/sap/My_SRV/entityset2?$filter=(serialno=122333)
I am now trying to retrieve the value from the entityset2 and trying to bind it to one attribute in my list. This list is already binded with the entityset1 data.
Myview.xml.
<List id="list" select="_handleSelect">
<ObjectListItem id="MAIN_LIST_ITEM" press="_handleItemPress" title="{Name}">
<attributes>
<ObjectAttribute id="ATTR1" text="{serialno}" />
<ObjectAttribute id="ATTR2" text="{entityset2/hdata}" />
</attributes>
</ObjectListItem>
</List>
Controller.js (binding using the below lines)
this.oList.bindAggregation("items", {
path: '/entityset1',
template: this.oListItem,
filters: this.searchFilters
});
var oserialnum = this.getView().getBindingContext().getObject().serialno;
var oHdata = new sap.ui.model.Filter("serialno", "EQ",oserialnum);
this.searchFilters = new sap.ui.model.Filter([oserialnum],true);
this.oList.bindAggregation("items",{
path : "/entityset2",
filters :this.searchFilters
});
However I am getting an error "Cannot read property 'getObject' of undefined" on this line "this.getView().getBindingContext().getObject().serialno".
Can someone kindly advise how to retrive the data from the entity2 and binding it to the list, ?
You cannot get BindingContext using the view. Read more about binding Context - it's a pointer to an object in Model data.
Also, serialNo(the parameter you are trying to retrieve from the Model is also contextual i.e. it differs with each row item).
One way to do this would be:
onListeItemPress Event of the List
<ObjectListItem ... ... press="onListItemPress" >
In the corresponding Controller
`onListItemPress : function(oEvent){
var oserialnum = Event.getSource().getBindingContext("mainODataModel")..getProperty("serialNo")`
Let me know if this helps.
If I understand you correctly what you need is associations.
They will allow the OData Service to deliver the needed Data from entityset2 directly with the entityset1 through "associating" entityset2 with your serial number.
If you are using a SAP Backend and SEGW this Blog might help you:
https://blogs.sap.com/2014/09/24/lets-code-associationnavigation-and-data-provider-expand-in-odata-service/
I was faced with a similar issue whilst creating a Master-Detail App, but found out from the SAP Forums that this is not possible, which makes sense and ended up creating a separate entityset in the Backend having a link to the other set
I have three tables, 'sessions', 'classes' and 'schedules' which they are connected each other.
sessions: id, name, descr
classes: id, session_id, name
schedules: class_id, session_id, date
A class belongs to a session, while the schedules is a N:M relations which gives the opportunity to have particular date for each session within a single class.
My problem comes when I have to display these information, I have a function which displays all Sessions:
$sessions = Session::all();
and I have another function which displays the date of a specific class and a specific session as below:
$result = Schedule:where('class_id','=',$classId)->where('session_id','=',$essionId)->first();
So let say I have 30 sessions for a single class, when it comes to my front-end app which is written in AngularJS I dont know how to handle the displaying here using the ng-repeat iterating thru all sessions and then make another call withing the ng-repeat iteration to call the schedule to display the date of the session, this is not a good practice I guess in AngularJS.
Could anyone tell me what would be the best option for me to handle this problem? Shall I have to modify the back-end? like edit the Session:all(); query to include also the Schedule table? or what is the best way?
I supposed you have already config your relations in models, if not look here
As for me, I use Fractal to customize display data. Also there is convenient method called Available includes
So you can request your data like /sessions/?include=classes and get output
{data: [{
session_id: 1,
some: "data",
classes:[{
class_id: 11,
some: "class_data"
}]
}]}
I would "eager load" the data, so you can access all the object's parents through the object you loaded. This way you can fill your table rows one by one by just iterating over 1 object.
There is excellent documentation about eager loading at the Laravel website, so I suggest you start there
I'm having massive problems with databinding to a ListView in a Windows 8 app using Javascript.
Inside the "activated" event on default.js I have written some code to get some data from a web service and push it into an array. This bit works OK and the array is populated.
The problem I have is that the app won't recognise the data. I have this code in a page called inspections.html:
data-win-options="{itemTemplate: select('#imageTextListCollectionTemplate'),
itemDataSource: dataList.dataSource,
layout: {type: WinJS.UI.ListLayout}}
and then in the "activated" event I declare:
var dataList = new Array();
and push the data from the web service into this array. But at runtime I get an error that says something along the lines of "can't find dataSource on undefined dataList".
I've done some of the examples on the MS website and in one of them it creates a dummy dataset and references it from a namespace. I kinda think that what I'm missing here is a namespace too but I don't know what the namespace for default.js is. Or maybe I'm wrong and it's something totally different.
Please help - this is so fundamental (and should be easy) but I can't get my head around it.
Do you want to create datalist in HTML or javascript?
It seems you want to create it from JavaScript. Assuming that you have already pushed your data into array from your webservice, you only need to call:
var dataList = new WinJS.Binding.List(array);
now accessing dataList.dataSource is perfectly valid.
Also, to create the datalist you don't always need an array. You could probably start with an empty list and then keep inserting data directly into the data list from web services, like:
var dataList = new WinJS.Binding.List([]);
dataList.push(value1);
dataList.push(value2);
...
Hope it helps. Let me know if you have any more questions.
If you are getting troubled by assigning datasource in HTML side
Prefer js side like
var list = new WinJS.Binding.List(array here);
listView.itemDataSource = list.dataSource;
by using this you can easily go through the data which you are binding to ListView.
I wanted to develop a Django app and one of the functionalities I'd like to have is dynamic drop-down lists...specifically for vehicle makes and models...selecting a specific make will update the models list with only the models that fall under that make....I know this is possible in javascript or jQuery (this would be my best choice if anyone has an answer) but I don't know how to go about it.
Also, I'd want the make, model, year and series to be common then the other attributes like color, transmission etc to be variables so that one needs only enter the make, model, year, and series only for a new vehicle. Any ideas would be highly appreciated.
The 3 things you mention being common, make, model, year, would be the 3 input values. When given to the server, an object containing the details would be returned to the calling page. That page would parse the object details (using JavaScript), and update the UI to display them to the user.
From the Django side, there needs to be the facilities to take the 3 inputs, and return the output. From the client-side, there needs to be the facilities to pass the 3 inputs to the server, and then appropriately parse the server's response.
There is a REST api framework for Django that makes it rather easy to add the "api" mentioned above -- Piston. Using Piston, you'd simply need to make a URL for that resource, and then add a handler to process it. (you'll still need to skim the Piston documentation, but this should give you an idea of what it looks like)
urls.py:
vehicle_details = Resource(handler=VehicleDetails)
url(r'^vehicle/(?<make>.*)/(?<model>.*)/(?<year\d{2,4}/(?P<emitter_format>[a-z]{1,4}), vehicle_details, name='vehicle_details'),
handler.py:
class VehicleDetails(BaseHandler):
methods_allowed = ('GET',)
model = Vehicles #whatever your Django vehicle model is
def read(self, request, *args, **kwargs):
# code to query the DB and select the options
# self.model.objects.filter()...
# Build a custom object or something to return
return custom_object
This simply sets up the url www.yoursite.com/vehicle/[make]/[model]/[year]/json to return a custom data object in JSON for jquery to parse.
On the client side, you could use jquery to setup an event (bind) so that when all 3 drop downs have a value selected, it will execute a $.get() to the api URL. When it gets this result back, it passes it into the Jquery JSON parser, and gives the custom object, as a javascript object. That object could then be used to populate more drop down menus.
(Big warning, I just wrote the following off the top of my head, so it's not meant to be copy and pasted. It's just for the general idea.)
<script type="text/javascript">
// On document load
$(function() {
$('#dropdown_make').bind('change', checkForValues());
$('#dropdown_model').bind('change', checkForValues());
$('#dropdown_year').bind('change', checkForValues());
});
function checkForValues() {
if ($('#dropdown_make').val() && $('#dropdown_model').val() && $('#dropdown_year').val())
updateOptions();
}
function updateOptions() {
url = '/vehicle/';
url += $('#dropdown_make').val() + '/';
url += $('#dropdown_model').val() + '/';
url += $('#dropdown_year').val() + '/';
url += 'json/';
$.get(url, function(){
// Custom data object will be returned here
})
}
</script>
This is uncanny: Dynamic Filtered Drop-Down Choice Fields With Django
His question:
"Here is the situation: I have a database with car makes and models. When a user selects a make, I want to update the models drop-down with only the models associated with that make. ... Therefore I want to use Ajax to populate the data."
You're not the same guy? :)