Ember.js adding and removing views from the DOM? - ember.js

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.

Related

ember.js beginner advice required

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

How to make a statically binded rendering editable via Experience Editor (Sitecore MVC)

So I have a layout view within Sitecore Mvc, this view contained a Controller Rendering that pulls in a header and footer navigation. Example:
#Html.Sitecore().Rendering("/sitecore/layout/renderings/some_rendering")
This specifies a Controller Rendering I've defined in Sitecore. This works great, except when I'm in the experience editor. It doesn't give me the ability to select this rendering. If I create a Placeholder and then define these navigation elements to this placeholder dynamically via Sitecore, then I can, but these navigational elements exist on every page of this layout, so I would like them statically placed instead of using a Placeholder, but I would still like the user to be able to select the navigation element in the experience editor (so I can create custom command to interact with this navigation, such as creating new links, etc).
Does anyone have an idea that will help me achieve this?
Use Edit Frame for that and create Custom Edit Frame Button for operations like adding new element to the navigation.
And remember to pass Datarsource ID or Path as a second parameter to the Html.Sitecore().Rendering() method:
#Html.Sitecore().Rendering("/sitecore/layout/renderings/some_rendering", new { DataSource = "{some-id-or-path}" })
Here is set of blog posts which can help you to understand how Edit Frames work and how to add them in Sitecore MVC solution:
https://visionsincode.wordpress.com/2015/01/08/how-to-use-editframe-in-sitecore-mvc/
https://www.cmsbestpractices.com/how-to-properly-use-sitecore-edit-frames/
https://briancaos.wordpress.com/2011/11/28/using-sitecore-editframe-in-pageedit/
You won't be able to remove the component or move it around the page (yeah, it's statically bound to one place on your layout), but you will be able to edit it's properties and datasource.
You can try to use GlassMapper views and statically inherit the view from the GlassView.
Then you'll be able to use Editable method to render the field.
But the consideration you need to take is that you'll not be able to set a datasource to the component from the page editor or content editor.
Instead of injecting the rendering through the Rendering method you should be able to use standart MVC RenderPartial.
I've used this approach on one of the projects I've been on and it worked.

MS Access Web App: set filter on sub view based on master view

My application has a list view (master) containing a data sheet view in a sub view element.
In the list view, I would like to use some control like a button or a combo box to filter the data in the sub view. How can I pass a parameter for the filter from the master view to the sub view?
I don't believe the scenario you are looking at here will be directly possible within the Access web app context. Let me explain.
In Access 2013 web apps, there is no macro action available to requery or refresh a specific control on a view. The same goes for trying to refresh a Subview control on a view. The only way you can pass parameters to a different view in the web app context is by using the OpenPopup macro action. In that case the view will open as a popup which is not what you want here either.
So you might not be able to achieve your end goal. One suggestion that might work is to have say an unbound text box control on the main parent view. For the Subview control, use that unbound control as the Master Field (in the property list). Access will attempt to match records from this unbound control to whatever field you designate as the Child Field property. If you update that unbound text box control on the main view, Access should filter the results in the Subview. I "think" that will work.
It works in my app. SubForm updates with filter when focus leaves the txtbox. Unfortunately, you can only search one field per subview as it is set as a property at design time and AFAIK there is no way to change at runtime.

Using page sections as route in emberjs

I'm working with a design that has a couple of sections on a single state, and I'd like to be able to link to each section individually.
Is there a way I could render a single template with no outlets at a base level, and then trigger a scroll when transitioning into any of the sub routes?
Additionally, is there a way I could prevent a transition from altering the browsers history, so I could transition around states as the user scrolls without forcing them to hit back several times to escape the page?
The main application template must have an outlet. Else you won't be able to render anything unless you want to do manual rendering with {{render}}. You could put some logic in the template to use with {{render}} but it seems overkill to avoid the convenience of {{outlet}}
You can model your state as a sub state with routes like, post, post/new, post/delete which correspond to routes nested in a post resource.
But, I don't think you can selectively use a route and not affect the url. You can only set the location to none to turn off location changes completely.
I'd just make sure the UI has a contextual back button that takes the user back to the previous state, skipping over states as necessary. So users don't have to rely on the browser's back button too much.

How to ensure the same controller instance is referenced in two different places in ember

tl;dr: Ember is creating two instances of an ArrayController when I want only one. How do I ensure that my code is always referencing the same one?
The scenario
Using ember, I am trying to create a section of a page where potential buyers can select from two sets of options, then click a button to accept those options and redirect to another page based on their choices. Example:
However, when I click the button, it uses whatever was selected when the page first loaded, ignoring any actions in between.
Let's work through the code
When you click the Reserve Now button, it triggers an action on the LessonPackagesController:
#handlebars template
<a {{action bookLesson on="click"}}>Reserve Now</a>
Here's the action it triggers: (If you don't understand emberscript, imagine it's just pseudocode... that runs)
#LessonPackagesController
bookLesson: ->
window.location = #bookingUrl
The location it points to is currently outside the ember application, so I don't think transitionToRoute and its sibling methods are viable.
#bookingUrl is a computed property on the controller.
#LessonPackagesController
+computed chosenPackage lessonType
bookingUrl: ->
url = "/instructors/#{#id}/lesson_bookings/new"
url += "/#{#lessonType}"
url += "/#{#chosenPackage.name}" if #chosenPackage
url
To simplify, I've started out by setting #lessonType to a default ('private'), and we don't have to worry about how #id is being fetched, because it's working.
Before we get into the details of how #chosenPackage is updated, I put together some code that logs every time #chosenPackage is updated, confirming that both #chosenPackage and #bookingUrl are being updated as expected.
#LessonPackagesController
+observer chosenPackage
yolo: ->
console.log(#bookingUrl)
Whenever I click a lesson package, for example the six-lesson package, I see the following in my console: /instructors/58/lesson_bookings/new/private/six. This is exactly as I expected.
However, when I click the Reserve Now button, I get the following: /instructors/58/lesson_bookings/new/private. This is the #bookingUrl that exists before the #chosenPackage is updated.
The plot thickens
In further tests, I put a #content log in 'yolo', and found that the content was... an empty array. Putting this together with the null #chosenPackage in #bookLesson, I surmised that I was accessing two different instances of LessonPackagesController. Here's how I access it when updating the #chosenPackage (which triggers the #yolo function):
class App.LessonPackageController extends Ember.ObjectController
needs: ['lessonPackages']
selectMe: ->
#chosenPackage = this
+computed chosenPackage
chosen: ->
this == #chosenPackage
chosenPackageBinding: 'controllers.lessonPackages.chosenPackage'
chosenPackage: ''
I know that all the LessonPackageController instances interact with the same LessonPackagesController because selecting one will deselect the current chosen package. However, it happens to be different than the instance which #bookLesson is called on.
How do I ensure those two instances are in fact one instance, the same instance?