I'm kind of new to Emberjs and I'm having trouble using select2 addon.
The docs were completely useless, I couldn't get a single info from there. Now I want to make the user to be able to select multiple data gathered from the database I tried using "model" in the "content" section but it's not working.
Here is the sample I took from the docs
{{select-2
content=patients
value=patients
multiple=true
placeholder="Choose some Pizzas"
}}
and my controller
patients: Ember.computed(function(){
return this.store.findAll('patient')
}),
It sounds like I need to loop through the record from the database, either that or I need to follow a convention where the object needs to have an id, name and a description, I even tried to use "patient.name" but it won't work. I also tried to add the sample to a component "don't know why" but it made the whole app crashes and shows nothing but a white screen (no errors in the console).
A mentioned in comment, ember-select2 is deprecated in favour of power-select addon. You can view great documentation for all possibilities.
{{#power-select-multiple
options=patients
selected=name
placeholder="Select some names..."
onchange=(action (mut name))
as |patient|
}}
{{patient.name}}
{{/power-select-multiple}}
and in controller,
patients: Ember.computed('model',function(){
return this.store.findAll('patient')
}),
Here is the working twiddle for demonstration. to kick start your journey with power-select.
Related
I'm new to ember-data. I'm trying to load comment list from a API using multiple API calls. The comment list feature works like below,
A comment object can have a parent comment or children comments (replies)
All comments (children & parent) from different comment threads are list down in a single comment list using a 1st API call.
If user click on specific comment from above list it will prompt respective comment thread. Respective parent or children comments loading using 2nd API call
The comment model is implemented as below,
export default CommentModel.extend( {
parent: computed(function() {
return get(this, 'store').queryRecord('comment', {
_overrideURL: `comments/${get(this, 'id')}/parent`,
});
}),
children: computed(function() {
return get(this, 'store').query('comment', {
_overrideURL: `comments/${get(this, 'id')}/children`,
});
}),
...
As this implementation, if user click on child comment (reply) from the comment list, the 2nd API call with load the respective parent comment and parent comment will load its children comments again. That behaviour cause reload the comment list component in UI.
Is there any other way in ember-data to lazy load relationship without creating already existing objects?
If you really need to go that road, you may try to perform a findRecord instead of a queryRecord and use adapterOptions to customize your model's adapter urlForFindRecord method.
TL;DR
Why you shouldn't:
IMHO, you have a data flow problem in your proposed design.
You shouldn't be performing async code inside a computed property (nor returning immutable object as queryRecord response).
Tasks work great for that purpose.
You shouldn't be having your model to load data (that should be route's responsibility), which violates both MVC and DDAU principles.
There is this great article from 2015 on that
As a matter of fact since ember octane, you shouldn't be using computed properties at all, they have been replaced by actual getters and tracked properties.
More on that
Ember is a great framework, good luck on your journey!
I have a component listing-table which takes a number of properties, like this:
{{listing-table model=model.devices type='user' exclude='customerName'}}
This works as intended, and the integration tests also work just fine. However, my acceptance tests fail, because apparently my exclude property is not being taken into account while running an acceptance test.
I have tested this by printing to console the value of this.get('exclude') in the component's javascript file and getting undefined. However, printing e.g. this.get('type') yields the expected results.
I have then, for testing purposes, removed exclude and replaced type's value with it, i.e. type='endpointName,typeName', however, I would get the previous value in the console, e.g. user.
This is all way beyond puzzling, and I'd really like to know what's the matter with acceptance test. Any sort of hints are more than welcome, and thanks for your time!
EDIT:
I have now edited my acceptance test to exclude clicking through various elements to get to the route that contains my listing-table component:
From:
visit('/users/1')
click('a:contains("Devices")')
To:
visit('/users/1/devices')
And the test passes. I still don't understand why clicking through makes my component's properties disappear, whereas visiting the page directly works just fine.
EDIT 2:
So, here is some sample code. This is what my test looks like:
test('/customers/1/devices should display 5 devices', function (assert) {
let type = server.create('endpoint-type')
let user = server.create('user')
let endpoint = server.create('endpoint', { type })
server.createList('device', 5, { user })
visit('/customers');
click('a:contains("Customer 0")')
click('a:contains("Devices")')
andThen(function () {
assert.equal(find('.device-listing').length, 5, 'should see 5 listings')
assert.equal(find('th').text().trim(), 'IDModelManufacturerMACExtensionLocation', 'should only contain ID, Model, Manufacturer, MAC, Extension, and Location columns')
})
Now, my Devices table should, in this case, omit the 'Customer' column, however, the column does appear in there, even though my component in devices.show.customers has been invoked with:
{{listing-table model=model.devices type='user' exclude='customerName'}}
My listing-table.js file basically uses this.get('exclude') inside the init () function to process the excludes, but as I said, if I add a console.log(this.get('exclude') in that file, I get undefined.
EDIT 3:
After more testing, I have made some progress, and the resulting question needs its own page, here.
Just a few thoughts:
I assume this one has been done since you got green on your second attempt... are you using andThen to handle your assertions to make sure all of your async events are settled?
Is the model hook being triggered? Depending on how you enter the route, the model hook will sometimes not get triggred: Why isn't my ember.js route model being called?
Might be helpful to have some code to look at.
I have a form create with dynamic form following the tutorial in the cookbook now I want catch when some input change so how can add (change) events, send the function to call as param; something like
new TextboxQuestion({
key: 'test',
label: 'Test ',
type: 'text',
onChange: 'test()',
order: 0
})
thanks
Since you're creating this form dynamically, you should therefore have access to it in your controller. Angular 2 uses the concept of the FormControl which is a very powerful tool for interacting with your form controls. I'll skip a lot of the details, but I'll point out a couple of things:
You've got access to FormControl.valueChanges, which might not be apparent from that doc because FormControl inherits from AbstractControl, a superclass that provides a huge chunk of useful functionality, much of which is very similar to the Angular 1 forms functionality.
Essentially, what you're looking to do is leverage observables. If you're unfamiliar with them, you should read about them. Christoph Burgdorf has a great article on them and actually, conveniently for you, uses FormControl.valueChanges as part of his example on how to use them. Oh what a lovely day it is!
But basically, in a nutshell, you're looking to do something along these lines:
this.textboxControl.valueChanges.subscribe(value => {
//... do your stuff here with 'value'
});
This obviously assumes that you've got an instance of the form control that you're wanting to react to.
IT IS EXTREMELY IMPORTANT that when using observables you UNSUBSCRIBE in the ngOnDestroy method in your controller; otherwise the subscription will hang around after you're done with it and you have a memory leak.
I am working on a Meteor application and am trying to pass an attribute of an item in a collection to a javascript function. In this instance I working with instafeed.js, a javascript plugin for the instagram API, but I would like to understand the process on a more fundamental level.
I’ve been able to pull records from my Teams collection into the /teams/:id route, and display attributes of a team using the {{name}} and {{igHandle}} template helpers.
I have also been able to get instafeed.js to work, using this package etjana:instafeed and the demo provided online. The tag I am pulling is assigned statically via:Session.setDefault(‘tagName’,’football’);
Eventually I would like to pull the user profiles, but that requires an access token from oauth2. I think that can be achieved with a {{$.Session.get access_token}} handlebar helper, but I need to figure out to feed a variable into the instafeed.js function first.
Could someone please explain how to pass the {{igHandle}} attribute through to the tagName in the javascript function. My code is as follows:
Team Template:
<template name="teamView">
<div class=“ui container”>
<h3>{{name}}</h3>
<p>
<i class="fa fa-instagram fa-lg"></i>
<a target="_blank" href="http://instagram.com/{{insta_hndl}}"> {{insta_hndl}}</a>
</p>
<br>
<h3>Instagrams</h3>
{{> igTeamFeed}}
</div>
</template>
Everything works, except the {{>igTeamFeed}} render. I am able to get content to show, but it is currently static. (assigned via (Session.setDefault('tagValue','football').
Instafeed Template:
<template name="igTeamFeed">
<div class="ui container”>
<h3>#{{insta_hndl}} Instagram</h3>
<div id="instafeed"></div>
</div>
</template>
Content is displaying, but again only through the static (Session.setDefault('tagValue','football') code.
Router:
Router.route('/teams/:_id', {
name: 'teamView',
template: 'teamView',
data: function(){
var currentTeam = this.params._id;
return Teams.findOne({ _id: currentTeam });
},
action: function() {
if (this.ready()) {
this.render('teamView');
} else {
this.render('loading');
}
}
});
Works with template helpers, so I am thinking I am ok here. Also following the instructions of a user per one of my prior posts.
Instafeed Javascipt: (needs some work)
Template.igTeamFeed.helpers ({
igData: function() {
return Session.get('insta_hndl');
},
});
Template.igTeamFeed.onRendered(function () {
//clear any previously stored data making the call
Session.get('insta_hndl'); //extra add-in
Session.set('insta_hndl', null);
Session.set('insta_hndl', this.data.insta_hndl); //extra add-in
var igHandle = this.data.insta_hndl;
});
Tracker.autorun(function(){
feed = new Instafeed({
get: 'tagged',
tagName: Session.get('insta_hndl'),
clientId: ‘xxxxxxxxxxxxxxxxxxx’,
resolution: 'thumbnail',
sortBy: 'most-liked',
limit: '15'
});
feed.run();
});
I have a helper to get the current insta_hndl for the session. The session item is passed through the team/:_id tag of the url, and defined in the router
The onRendered is wiping out the old handle, and inserting the new one. I added two additional Session.get and Session.set functions since I was getting an error that insta_hndl was undefined (differing from the response on my previous post). Could be wrong there.
The tracker.autorun function was code I had working with an instafeed example. Should it be somewhere else? Maybe in a helper or onRendered function? Also do I need tracker.autorun to use instafeed? To my understanding it dynamically updates the feed when a tagName changes, but aren't there other ways to do this?
How to Solve
These are some ways I'm thinking I could to solve this. Please advise on how to do this / what you think is best practice:
Collection Helpers: Was thinking I could call something like Teams.findOne().insta_hndl but didn't have much luck. Is that the right code block to use? Do I have to define a variable in the template helper, or can I call it directly in the feed js function?
Handlebars Helpers: Thinking I could do something with a Session helper, but not sure if it would work if one user had two different instances of the instafeed open (two tabs open with different teams selected).
Reactive Methods: Allows one to call methods synchronously inside Tracker.autorun. Thought i read something that said Meteor already has this functionality baked in, but please advise.
Iron Router Query: Part of me still isn't convinced the insta_hndl isn't getting passed through. I've explored adding the instagram handle as a query param to the URL, but do not think this is a best practice.
If someone could help me get this working that woudld be great, but explanations would even better! Really spending a lot of time on this, and many of the online resources are using depreciated syntax.
Also two more related questions questions:
Should I use a controller? Should i write out a controller separately? Or just include it in Router.route functions? Seeing some people rely heavily on controllers, but a lot of documentation does everything through Router.route.
Should I break out the instafeed function into a method? If so how should I do this? I spent a great amount of time tryig to set up the whole instafeed function as a server side method, but couldn't seem to get it to work. I only foresee myself using this function in one or two other templates, so I figured it was fine to leave as is. Please advice.
Sorry that this was a bit confusing. The correct javascript is:
Template.igTeamFeed.helpers ({
teams: function() {
return Teams.find();
}
});
Template.igTeamFeed.onCreated( function() {
var igHandle = Teams.findOne(Router.current().params._id).insta_hndl;
feed = new Instafeed({
get: 'tagged',
tagName: Session.get('insta_hndl'),
clientId: ‘xxxxxxxxxxxxxxxxxxx’,
resolution: 'thumbnail',
sortBy: 'most-liked',
limit: '15'
});
feed.run(); //run the new Instafeed({})
});
There is no need for any of the things I suggested. The attribute can be grabbed with Collection.findOne(Router.current().params._id).attrib, where Collection is your collection and attrib is the non-_id value you want to grab.
Also did not need tracker.autorun, that was throwing me off as well.
I have an select box which contains list of 350-400 <option> element. The element data is loaded via ajax. Which loads fine.
But when I ember tries to create the list. The browser hangs with high RAM and CPU uses finally unresponsive script error is shown in browser. Given enough time it renders.
It also seems that ember doesn't really caches the rendered element because every time I comeback to the same page the problem repeats.
So, Is there any way I can improve the performance of the view select?
The sample code for the select view:
{{view "select" prompt="-- select --" content=controllers.application.companies
optionValuePath="content.id" optionLabelPath="content.name_abbr"
classNames="form-control" value=dailyId}}
I know one of the alternatives will be using a typeahead script using a text box. But I want to save it as a plan B for now.
Warning:
This solution is due to be deprecated as of Ember 2.0 according to this blog entry:
REMOVALS
....
Manually rendering a string into the buffer in a view
I don't think I have an answer for you, and I didn't come back to this 'cause I couldn't find the full implementation I've made a while back. It was essentially a copy of the current select component, except, like I said, I've implemented the render method. Something like this:
App.CustomSelectComponent = Em.Component.extend({
tagName: 'select',
optionValuePath: '',
optionLabelPath: '',
content: [],
render: function(buffer) {
var selfie = this,
options = this.get('content'),
idPath = this.get('optionValuePath'),
valPath = this.get('optionLabelPath');
options.forEach(function(option) {
buffer.push('<option value=\'' + option[idPath.replace(/^content\.?/, '')] + '\'>');
buffer.push(option[valPath.replace(/^content\.?/, '')]);
buffer.push('</option>');
});
}
});
This is NOT the implementation I had before, and if you spend a few seconds looking at it you will see some problems with this solution, however, the render implementation is what you might want to look into.
With the implementation as is, I can get a better performance already. On the jsbin I've added a small set of records for both Ember.Select and the sample custom-select:
But again, this implementation is lacking several features and is probably not enough to answer this question. I just did it a few minutes ago to sort of show were you'd start implementing the render and how, within your component.
Sorry if this isn't the answer you wanted.