I created a auto complete search bar in ember.js. The problem that i am having is be able to to press the down key and and go ever the listing that the autocomplete div is giving me. Thank you in advance...
<li {{bind-attr class="opacitySet:border:field"}}>
<i class="icon-search"></i>
{{input type="search" placeholder="Search Keyword" focus-out="focusOut" focus-in="focusIn" value=searchText}}
<div {{bind-attr class=":ee opacitySet::hide"}}>
{{#each searchResults}}
<h4><i class="icon-doc-text" style="padding:0;"></i>{{this}}<img src="assets/images/Arrow.png" class="pull_right"></h4>
{{/each}}
</div>
</li>
===========controller=============
App.FaqController = Ember.Controller.extend({
showAllAnswers: false,
opacitySet: false,
searchText: '',
searchResults: function(){
var searchText = this.get('searchText');
if(!searchText){ return;}
var regex = new RegExp(searchText, 'i');
return question.filter(function(name) {
return name.trim();
return name.match(regex);
});
}.property('searchText'),
actions:{
toggleBox: function(){
this.toggleProperty('showMessageBox');
},
hideBox: function(){
this.set('showMessageBox', false);
},
toggleAllAnswers: function(){
this.toggleProperty('showAllAnswers');
},
focusOut: function(){
this.set('opacitySet', false);
},
focusIn: function(){
this.set('opacitySet', true);
},
}
});
Related
I am still learning Ember and have encountered a problem with keep consistent behavior when showing/hidding certain elements in the template. I have the following controller
import Ember from 'ember';
export default Ember.ArrayController.extend({
actions: {
newCalendar: function() {
this.set('showCalendarForm', true);
},
hideNewCalendar: function() {
this.set('showCalendarForm', false);
this.set('calendarName', '');
},
showCalendarForm: false,
createCalendar: function() {
var name = this.get('calendarName');
if (!name) { return; }
if (!name.trim()) { return; }
var calendar = this.store.createRecord('calendar', {
name: name
});
this.set('calendarName', '');
this.set('showCalendarForm', false);
calendar.save();
},
}
});
and a template
{{#if showCalendarForm}}
<div class="input-group">
{{input
class = 'form-control'
id = 'newCalendar'
type = 'text'
placeholder = 'New calendar'
value = calendarName
autofocus = 'autofocus'
focus-out = 'hideNewCalendar'
action = 'createCalendar'
}}
</div>
{{else}}
<button class="btn btn-sm btn-primary" {{action "newCalendar"}}>New</button>
{{/if}}
Problem is that the input field only gets autofocused the first time I click the button, and on subsequent clicks, the input gets displayed, but not autofocused. How can i fix this?
Disclamer: I started using Ember.js few days ago
Suppose having these 2 models:
App.Question = DS.Model.extend({
text: DS.attr('string'),
answers: DS.hasMany('answer', {async: true})
});
App.Answer = DS.Model.extend({
question: DS.belongsTo('question'),
text: DS.attr('string')
});
For some reasons I got this JSON (without "answers" list)
{
...
"questions": [
{"id": 1, "text": "Foo?"}, ...
]
}
In the template I want to load and show answers only if explicitly needed
{{#each questions itemController="question"}}
<div class="answer-wrapper">
{{text}}
<button {{action "loadAnswers"}}>Load answers</button>
<ul>
{{#each answers}}
<li>{{text}}</li>
{{/each}}
</ul>
</div>
{{/each}}
How can I do this in the controller's loadAnswer action?
App.QuestionController = Ember.ObjectController.extend({
...
actions: {
loadAnswers: function() {
// programatically load answers
}
}
});
Workaround: I can do this changing the attribute in the template
{{#each loadedAnswers}}
<li>{{text}}</li>
{{/each}}
and defining correctly the action
App.QuestionController = Ember.ObjectController.extend({
...
actions: {
loadAnswers: function() {
// or loaded with ajax...
this.set("loadedAnswers", [
{id: 1, text: "foo"},
{id: 2, text: "bar"}
]);
}
}
});
You can wrap that portion of the template with an if statement. The async relationship won't be fetched unless it's requested.
Controller
App.QuestionController = Ember.ObjectController.extend({
showAnswers: false,
...
actions: {
loadAnswers: function() {
this.set('showAnswers', true);
}
}
});
Template
{{#if showAnswers}}
<ul>
{{#each answers}}
<li>{{text}}</li>
{{/each}}
</ul>
{{/if}}
I am using EmberJs version 1.4.
When I click on one of the links I would expect the URL to include the id of the selected widget but nothing appears and when I look at the params parameter in the route model hook it has no properties and I would expect the id to be one of its properties so could someone help me to understand what am I missing?
In other words I would expect the URL to become awesome.html#/widgets/5 but it always is awesome.html#/widgets
Thank you!
This is my ember code:
window.Awesome = Ember.Application.create();
Awesome.Router.map(function() {
this.resource("awesome", {path: "/"}, function(){
this.route('login');
});
this.resource("widgets", function () {
this.resource('widget', { path: '/:widgetId' }, function () {
this.route('general', { path: 'info' });
this.route('configuration');
this.route('operations');
})
});
});
Awesome.WidgetsRoute = Awesome.AuthenticationRoute.extend({
model: function(){
//TODO: Call a service to get the model.
return { widgets: [{ widgetId: 1, widgetName: "Great Widget" }, { widgetId: 2, widgetName: "Fantastic Widget" }, { widgetId: 3, widgetName: "Brutal Widget" }] };
}
});
Awesome.WidgetIndexRoute = Awesome.AuthenticationRoute.extend({
model: function (params) {
var receivedWidgetId = params.widgetId;
return { widgetName: "Hardcoded Widget", widgetId: receivedWidgetId };
}
});
These are the templates:
<script type="text/x-handlebars" data-template-name="widgets">
<section class="span3 left-section">
<div class="btn-group-vertical btn-group-justified registration-actions-menu">
<button id="createNewWidget" class="btn btn-link">Create New Widget</button>
<button id="joinWidgetTeam" class="btn btn-link">Join Widget Team</button>
</div>
<div class="registered-widgets-menu">
<div class="btn-group-vertical">
{{#each widget in widgets}}
{{#link-to 'widget' widget class="btn btn-link"}}{{widget.widgetName}}{{/link-to}}
{{/each}}
</div>
</div>
</section>
<section class="span8">
{{outlet}}
</section>
</script>
<script type="text/x-handlebars" data-template-name="widget">
<div id="widgetOptions">
<!-- TODO: Change the anchors for handlebars link-to helpers. -->
<h1>{{widgetName}}</h1> <h5>{{widgetId}}</h5>
<ul id="widgetNavigation">
<li>Widget Info</li>
<li>Widget Configuration</li>
<li>Widget Operations</li>
</ul>
</div>
<div id="widgetContent">
<!-- TODO: Design some awesome widget content. -->
Some awesome widget content
</div>
</script>
I also have an authentication route from which the other routes inherit. Even though I don't believe it has something to do with the issue I'll include just in case I am wrong.
Awesome.AuthenticationRoute = Ember.Route.extend({
beforeModel: function(transition){
if(!Awesome.get('loggedUser')){
this.redirectToLogin(transition);
}
},
redirectToLogin: function(transition) {
var loginController = this.controllerFor('awesome.login');
loginController.set('attemptedTransition', transition);
this.transitionTo('awesome.login');
}
});
It looks like it's totally working to me, when you click on one of the widgets
http://emberjs.jsbin.com/mohex/1
Additionally it looks like you're mixing up the WidgetIndexRoute and WidgetRoute. The widget resource should be displayed like this (though this is unrelated to the issue you're describing)
Awesome.WidgetRoute = Awesome.AuthenticationRoute.extend({
model: function (params) {
var receivedWidgetId = params.widgetId;
return { widgetName: "Hardcoded Widget", widgetId: receivedWidgetId };
}
});
I'm building an app that has the following code:
Routes:
App.Router.map(function() {
this.resource('gradebooks', function() {
this.resource('gradebook', { path: ':gradebook_id' });
});
});
App.IndexRoute = Em.Route.extend({
redirect: function() {
this.transitionTo('gradebooks');
}
})
App.GradebooksRoute = Em.Route.extend({
setupController: function(controller, model) {
Em.$.getJSON('/data/gradebooks/get', function(data) {
controller.set('model', data);
});
}
});
App.GradebookRoute = Em.Route.extend({
model: function(params) {
var id = params.gradebook_id;
return Em.$.getJSON('/data/gradebooks/get/' + id);
}
})
Controllers:
App.GradebooksController = Em.ArrayController.extend({
isActive: false,
actions: {
createGradebook: function(newTitle) {
var self = this;
if(newTitle.trim()) {
Em.$.get('/data/gradebooks/add/' + newTitle, {}, function(json) {
Em.$('#create-gradebook-modal').modal('hide').find('input').val('');
self.transitionToRoute('gradebook', json.id);
}, 'json');
}
}
}
});
Templates (gradebooks.hbs):
<div class="sidebar">
<div class="btn-container">
<button class="btn btn-block btn-info" data-toggle="modal" data-target="#create-gradebook-modal">
<i class="fa fa-book"></i>
Create Gradebook
</button>
</div>
<ul>
{{#each}}
<li {{bind-attr class="isActive:active"}}>
{{#link-to "gradebook" _id}}
{{title}}
{{/link-to}}
</li>
{{/each}}
</ul>
</div>
<div class="content">
<div class="container-fluid">
{{outlet}}
</div>
</div>
Templates (gradebook.hbs):
<h1>{{title}} <small>{{_id}}</small></h1>
<div class="btn-container">
<button class="btn btn-default"><i class="fa fa-pencil"></i> Rename</button>
<button class="btn btn-danger"><i class="fa fa-trash-o"></i> Trash</button>
</div>
What I'm having trouble with is under the GradebooksController.actions.createGradebook, I send a request to create the model and then I transition to the gradebook I just created. The creation and transition works just fine, but I want the sidebar (gradebooks.hbs) to show the newly created gradebook.
I think it has something to do with updating the model in the GradebooksRoute. How can I make it fetch for the models from the server again after creating a gradebook.
To elaborate on #fanta's comment, you'll want to do something like this:
App.GradebooksController = Em.ArrayController.extend({
isActive: false,
actions: {
createGradebook: function(newTitle) {
var self = this;
if(newTitle.trim()) {
var gradebook = Em.$.getJSON('/data/gradebooks/add/' + newTitle, {}, function(json) {
Em.$('#create-gradebook-modal').modal('hide').find('input').val('');
self.transitionToRoute('gradebook', json.id);
}, 'json');
self.get('content').pushObject(gradebook);
}
}
}
});
I'm looking for advice on how to trigger this view function insertNewLine from a button (see view and template below). I'm guessing there's probably a better way to structure this code. Thanks for your help.
// view
App.SearchView = Ember.TextField.extend({
insertNewline: function() {
var value = this.get('value');
if (value) {
App.productsController.search(value);
}
}
});
// template
<script type="text/x-handlebars">
{{view App.SearchView placeholder="search"}}
<button id="search-button" class="btn primary">Search</button>
</script>
You could use the mixin Ember.TargetActionSupport on your TextField and execute triggerAction() when insertNewline is invoked. See http://jsfiddle.net/pangratz666/zc9AA/
Handlebars:
<script type="text/x-handlebars">
{{view App.SearchView placeholder="search" target="App.searchController" action="search"}}
{{#view Ember.Button target="App.searchController" action="search" }}
Search
{{/view}}
</script>
JavaScript:
App = Ember.Application.create({});
App.searchController = Ember.Object.create({
searchText: '',
search: function(){
console.log('search for %#'.fmt( this.get('searchText') ));
}
});
App.SearchView = Ember.TextField.extend(Ember.TargetActionSupport, {
valueBinding: 'App.searchController.searchText',
insertNewline: function() {
this.triggerAction();
}
});