I am attempting to learn ember.js to produce a simple-ish web application. I have read around the subject and completed the basic tutorial on emberjs.com . So far, I have managed to create the beginnings of an API using PHP and I have been able to retrieve that data into my fledgling application. So far so good.
As a starter, I wish to retrieve a list of users from the server and populate a select with these values. The select is to sit on the menu bar and the selection from this drives the rest of the data for the application. I have placed the model in models/users.js. The application menu I have defined in templates/application.hbs (not sure if this is considered correct or not).
I am unable to get the users data for the select retrieved from the server unless I visit the users route that I have also setup. How can I ensure that the users data is populated at application initialisation? How would I apply/filter the rest of the application data upon selection from this component - would I need to set a global variable or something?
Additionally, I am using materializecss, which requires $('select').material_select(); to be run in order to render the select input. I have this as:
$( document ).ready(function(){
$('select').material_select();
});
in templates/route.js and works fine on initial page load, but upon navigation to another area and back again, the select is not rendered, and from what I have read, I need to call material_select() again, but I can't for the life of me work out where this call should go.
If anyone is willing to take the time to help me better understand things, I will be very grateful.
Cheers
Tim
Preloading Clarification
I wish to have a select box on the main menu bar (menu-bar component). The user will use this to select a user. All content in the app will be filtered to the currently selected user. I currently have an API endpoint (/users.php) which returns the required data, but I am only able to get my application to call this when I visit the users route, which obviously I won't be doing when the app loads initially. So I am thinking I need to preload the data somehow, unless there is a better way that I am not aware of?
Create a component for menu and put the component in application.hbs
And in component put the materialize stuff like this : (notice to the place)
//components/menu-bar.js
didInsertElement(){
this._super(...arguments);
Ember.$( document ).ready(function(){
Ember.$('select').material_select();
});
}
And
//templates/application.hbs
{{menu-bar}}
{{outlet}}
UPDATE
Create a service holding current user selection and use it in other places that you want be changed by changing the user selection.
These codes is just for showing that the solution for what you want (changing the other parts of app based on changing the selected user in menu) is services.
//services/current-selection.js
...
selectedUser: null,
...
and
//components/menu-bar.js
currentSelection: Ember.inject.service(),
actions: {
selectUser(user){
this.set('currentSelection.selectedUser', user);
}
}
and in another place you want to be notified when selection changed :
//components/user-info.js
currentSelection: Ember.inject.service(),
and corresponding template
//templates/components/user-info.hbs
{{#if currentSelection.selectedUser}}
<span>Current Username: <strong>{{currentSelection.selectedUser}}</strong></span>
{{/if}}
Update For pre-loading users
Actually it's not pre-loading
In menu-bar component you load a select box and populate it by calling a service to backend. If you put this component in application.hbs you could ensure what you want is satisfied.
//components/menu-bar.js
store: Ember.inject.store(),
users: Ember.computed(function(){
return this.get('store').findAll('user');
}),
OR
In application route model hook you fetch those users and pass to component like {{menu-bar users=model}}
And for these two options you can use users in menu-bar template.
But pay attention to that if the users count is a lot, this is very bad for performance or UX. If your users are a lot it's better to use from a autocomplete component
Related
Note: The English used in this article (along with the terms) may be a bit "out of order" since my native language is not English. Rest assured I have tried my best to make it as readable as possible, and if I have missed anything please do comment before downvoting so I may update the question accordingly (I'm still new to this)
So I've searched most of the internet for a solution to this, to find a tutorial that would guide me on the metadata driven approach for building an application on EmberJS. The documentation on Ember doesn't explain anything about the approach, just a function definition of extractMeta here, and a basic overview of how to handle metadata here.
What I want to achieve is to build a portal, with Sugar as the back-end for the application. The application will use REST API for making calls to extract the data as well as the metadata of the application. We want to make the application generic, so that no matter what module is called, the metadata is extracted to determine the fields required in the model, a filtered portion of the data needed from the call is populated into the model accordingly and the is displayed in a generic template, that will be global and used throughout the application.
The metadata includes various items such as buttons, panels, attributes(each with multiple layers of data within) etc, each may be used once or multiple times within the call or not at all. For example, for displaying the application would require the attributes for display within the table, as well as buttons for adding, deleting updating etc. Upon click the panel may be required for say, adding a particular record, which itself may contain various fields.
As an example, is the default Sugar instance that shows the leads in the data, notice how it contains various components.
Here, another example, of the panel that appears when I click the create button in the leads list, notice the fields that appear within the panel
Please Note that I do understand how to make the REST API calls for the data as well as the metadata. But how to turn that into a generic meta driven application is what I am struggling with. Thanks in advance!
If I understand this correctly, you're looking for some kind of generic UI builder based off of returned data from a REST endpoint. Ember provides the component helper.
The {{component}} helper can be used to defer the selection of a
component to run time. The {{my-component}} syntax always renders the
same component, while using the {{component}} helper allows choosing a
component to render on the fly. This is useful in cases where you want
to interact with different external libraries depending on the data.
Using the {{component}} helper would allow you to keep different logic
well separated.
{{#each model as |post|}}
{{!-- either foo-component or bar-component --}}
{{component post.componentName post=post}}
{{/each}}
Read here for a more thorough explanation.
What you essentially need to do is build a bunch of different components for each of the possible attributes from the metadata. Your models will contain what components they should render and you'll use the component helper to dynamically render the correct elements.
If you're using a table based approach, have a look at ember light table. They leverage this approach heavily with how they build the columns for their tables and support custom components:
columns: computed(function() {
return [{
label: 'Avatar',
valuePath: 'avatar',
width: '60px',
sortable: false,
cellComponent: 'user-avatar'
}, {
label: 'First Name',
valuePath: 'firstName',
width: '150px'
}];
})
As you see here, the columns are rendered generically and they use the cellComponent property to determine which component type to render.
I have a simple application that uses jqplot to graph data. This application has a single route attached to an ArrayController. I display the items to be graphed on the left side using the {{#each}} helper; I also display a 'graph' button up top. The user can select one or more entries from the list and hit the graph button. The button is attached to an action that calls jqplot to graph the selected data on the right side. Functionally, this works fine, but feels like a hack. Does anyone have an opinion on how this can be re-structured to perform similar function the 'Ember way'?
This app only has one model, so doesn't seem like I would need a second route. I do need to somehow handle re-graphing if the user resizes the window. If I weren't using Ember, I would handle window resizing like this:
$(window).resize(function(){
plot1.replot ({resetAxes: true});
});
where 'plot1' is the return value from the original call to jqplot.
How do I do this in Ember?
I'm using Ember 1.4 with EmberData beta 7.
You can put custom JS code in the didInsertElement() hook of your view, which will be executed after the view is rendered.
There's a corresponding willDestroyElement() hook for your teardown code.
I am building my first EmberJS app, and am still trying to wrap my head around the best practices & conventions. I'm using ember-data to talk to a RESTful API, and have ember-auth working well enough to log in and save a user's ID & OAuth2 access token. However, I'd now like to maintain additional user information (e.g. name, email, etc) for use in the navbar and in various other areas of the app.
To do this, I am thinking it would be helpful to have a User object (model) that is read from a separate endpoint (e.g. /users/<id>). Since this info would be needed throughout the app, I'm inclined to store it on the ApplicationController, somewhat like this example from Ember's docs:
App.ApplicationController = Ember.Controller.extend({
// the initial value of the `search` property
search: '',
query: function() {
// the current value of the text field
var query = this.get('search');
this.transitionToRoute('search', { query: query });
}
});
However, my user object wouldn't quite be an action like query or a property like search, so I'm not sure this example applies.
I think I'll eventually want to call something like:
this.get('store').find('user', App.Auth.get('userId'));
but I'm just not sure where in the app that would go.
Main question: is the ApplicationController the right place for this information per Ember conventions, and if so, what might the code look like to retrieve it from the REST API?
Appreciate any thoughts to put me on the right track.
The general approach that I've taken before is to store the currently logged in user as App.CurrentUser. Then you can use it in any template. Once I've pulled the User object I call Ember.set('App.CurrentUser',user) to store it, and then Ember.get('App.CurrentUser') to retrieve it in other routes or controllers.
Here's a short jsbin with the general idea : http://jsbin.com/ucanam/994/edit
I can work with Ember.js(rc0) and Rails, and have a simple app working as I'd expect, but want to focus on a specific story:
As a user, I want to type in "filter" text in a form, then have my ArrayController only show me those items that match the filter. For example, think of a Contacts app that shows people with the name like "Ya%"...
Caveat: Say the database holds thousands of Contact records. I don't want to filter those contacts on the client, it makes more sense to do that on the server.
Question:
How do I do this in ember.js/ember-data? On the server, I can easily allow for a search parameter in my index URL to filter data so it's a manageable list, or even limit the response to say, 20 items.
I can also use a view to have access to my filter text in my controller, but where do I go next? How can I pass that filter onto the server?
Update:
I was able to use "find" on the model object, and ember (ember data) went to the server to grab new data - as the client side only had a subset of all the Contact records to begin with. Instead of filtering on what on the client, it automatically deferred to the the server... which is nice.
App.ContactIndexController = Ember.ArrayController.extend
search_term: null
submit: (view) ->
this.set('content', App.Contact.find({search: "#{view.search_term}"}))
This is a good use case for findQuery. For example:
store.findQuery(App.Contact, {q: queryString})
This will in turn call findQuery on the appropriate adapter, and if successful, load the returned records into the store and return a DS.AdapterPopulatedRecordArray.
Note that you can completely customize the query object to include params that match your server's endpoints.
Update: As Michael pointed out in the comments, the above is equivalent to:
App.Contact.find({q: queryString})
... which is certainly a cleaner solution, especially without direct access to the store.
I am looking into ember.js, after working with SproutCore 1 previously. I am looking for some examples on how to add and remove views from the DOM as the user navigates the application.
For instance, I have an application that contains a set of cases and each case has a workflow. There are also administration pages, etc.
When the user starts up the app, a dashboard-like user interface is shown. From here the user is able to search or click on a case in order to bring up that case. At this point I want to do the following:
I want to remove the GUI for the Dashboard, and i want to show the GUI for the case - which is a complex GUI in itself with its own set of navigation rules etc.
Also, within the case I want to add and remove portions of the GUI as the user navigates and manipulates the case.
When the user clicks on the "Dashboard" link, I want the current GUI to be removed, and the dashboard to be added again.
As this will be a somewhat large application I am not sure if toggling the isVisible parameter is sufficient, or if other measures needs to be taken in order to not overload the user's browser.
Is there a guide, or an example that shows how to do this ?
WARNING: OUTDATED ANSWER
A view inherits from Ember.View which means it gets some key methods. append(), which appends to body, appendTo(arg) which takes an argument and remove().
The argument is a jQuery style selector of where to insert the element in the DOM.
// my view
App.PartsView = Ember.View.extend({
...
});
// create/insert my view
App.partsView = App.PartsView.create();
App.partsView.appendTo('#partcontainer');
In my code I have a <div id="partcontainer"></div>.
// remove from DOM
App.partsView.remove();
The documentation has a good part on Building a View Hierarchy and later a section on Ember.ContainerView depending on whether you want to do it all programatically or not.