How do you bind attributes in an enyo kind? - enyo

I am having problems creating a Tweet() kind instance and having the span content be "hoho" even though line 60 should set it - https://github.com/metaperl/enyo-identica-tutorial/blob/master/source/App.js#L60
I also tried t.setText("hoho"); but that did not work either.

You should be calling setText() instead of violating the encapsulation of the tweet kind. However, the problem appears to be the call to addContent(). This doesn't do what you think it should. Either you want to call addContent() with t.getText() or you want to actually add the new tweet control to the scroller. addContent() expects to get a string passed in (see: http://enyojs.com/api/#enyo.Control).
You probably want to instead do something like this:
reloadTweets: function() {
this.$.main.createComponent({kind: "Tweet", text: "hohoho"}, {owner: this});
this.$.main.render();
}
Although, what you probably -really- want to do is directly add tweets to the scroller or create a flyweight list and add the items to that.

The answer is here which is close to Pre101's suggestion.
Here is my working code:
reloadTweets: function(inSender, inEvent) {
this.$.main.createComponent({
kind: "Tweet",
text: "ho ho ho ho"
});
this.render();
}

Related

What is the best way to extract component information that is intersected with raycaster?

Is there any way to extract the entity's information(id, class, etc) that is intersected with a raycaster?
I tried to find the information from evt.detail.el but no success.
AFRAME.registerComponent('collider-check', {
init: function () {
this.el.addEventListener('raycaster-intersected', function (evt) {
console.log(evt.detail.el);
});
}
});
The issue is that the code above logs the raycasting entity, rather than the raycasted entity, so it is logging the cursor.
Using the code above, you can access the data you need by logging evt.detail.intersection.object.el. So you could do something like the following to access id and class, respectively:
console.log(evt.detail.intersection.object.el.id);
console.log(evt.detail.intersection.object.el.className);
Here is a demo of the code in action: https://codepen.io/dansinni/pen/bjjbWv
If you haven't bound this to the handler, and only need basic attribute data, you should also be able to do the following, but YMMV:
console.log(this.id);
console.log(this.className);
You should also be able to use a component with the cursor instead, and rely on the raycaster-intersection event. Note the difference in the docs: https://aframe.io/docs/master/components/raycaster.html#events

How to update using angularFireCollection which items not exist previously

I have this parent node with text and I want to add a media into the parent node also if the text is changed will update as well.
{
parent: {
text: 'this is content'
}
}
The media value from a third-party callback. How to pass it to update()? I tried {media: callbackVal} but not working.
$scope.parent = angularFireCollection(firebaseRef.child('parent'));
$scope.parent.update(What_to_do_here, function(error){
//something...
});
UPDATE
Maybe my question is not clear enough.
In Firebase JS, we can do this to update or insert media into the node.
new Firebase(firebaseRef).update({ media: 'value'} );
How to do this in `angularFireCollection ?
Check out the annotated AngularFire source: http://angularfire.com/src/angularFire.html#section-38
It looks like AngularFireCollection.update() takes a key/item and a callback function. So you need to edit the entry you want to update directly in your AngularFireCollection, (e.g. $scope.parent.getByName('media').value = 'alligator scrimshaw') and then call $scope.parent.update($scope.parent.getByName('media'), function(err) { ... }).
NOTE: One rather confusing thing (which maybe I am misunderstanding) is that there doesn't seem to be a way to add data to an AngularFireCollection by id. So if media doesn't already exist in your Firebase, $scope.parent.getByName('media') will return undefined. For this reason, if you don't need explicit syncing, and implicit syncing is fine, I would use an AngularFire object instead of an AngularFireCollection.

can I bind a value to a part of an object from elsewhere in the model?

I have a model that has (for example) shopping cart item IDs and a list of available items to add to the cart. It's a fake example.
table#items
tbody
tr(ng-repeat="item in cart.items")
td.hide {{item.id}}
td {{availableItems.where(id: item.id).first.name}} <-- pseudo code
td ({{item.shippingType}})
What I'd like to do is bind the second cell to the name of the item from the list of available items, rather than cluttering up the model by having that value in 2 places. Would I use a filter function to do this? The docs are very simplistic. How can I pass item.id to the filter function?
I've gotten closer with this in the markup:
td {{availableDatasources | filter: itemNameById}}
and this in the scope:
$scope.itemNameById= function(item) {
lodash($scope.availableItems).find({
id: item.id
}).name;
};
Only problem is I don't get a name back (even though that's what the filter seems to be returning) -- I get all of the available items. It's hitting the filter code but the filter seems to not be filtering.
Honestly, I'm not sure this is worthwhile. Your cart is probably just an array of references to objects in your availableItems array, so you're not really repeating anything.
But if I wanted to do as you say, I would include underscore.js in my project.
http://underscorejs.org/
Then in the controller, I would add underscore to the scope:
$scope._ = _;
In my template I would write
td {{_.findWhere(availableItems, {id: item.id}).name}}
Or, more likely, I would add a more specific function to my scope:
$scope.productFromId =
function(id) { return _.findWhere($scope.availableItems, {id: id});};
And then in the template:
td {{productFromId(item.id).name}}

Subscribing to changes in a Collection but not in a template

I'm very new to meteor, so apologies if I'm missing something very basic here.
I thought it would be fun to create a very simple textpad style app to check out meteor. I took the todo app and changed the data structures to be 'folders' and 'docs' rather than 'lists' and 'todos', so I have a list of folders and when you click on the folder you get a list of the documents in that folder.
I've then added some code to show the 'content' attribute of a single 'doc' when one of the docs in the list is clicked.
I'm using ace to add some pretty print to the content of the doc (https://github.com/ajaxorg/ace). I've set ace up to work with a hidden textarea containing the plaintext version of my document, and the editor object takes this text and pretty prints it.
The problem with ace is that I don't want the template containing the ace editor to be replaced every time the contents of the doc changes (as it takes half a second to reinitialise, which is a crappy experience after every character is typed!). Instead, I want to update the textarea template and then use the ace API to tell the editor to update it's input based on what is in the textarea.
Now, this is probably the wrong way to approach the problem, but I've ended up using two templates. The first contains a textarea containing doc.contents, which is reactive to the underlying model:
<template name="doc_content">
<textarea name="editor">{{content}}</textarea>
</template>
The second one contains the 'editor' div which ace uses to display the pretty printed text.
<template name="doc_init">
<div id="editor"></div>
</template>
The idea is that the first template will update every time the user types (on all clients), and the second template is only ever re-loaded for each new doc we load.
Template.doc_content.content = function() {
var doc_id = Session.get('viewing_itemname');
if (!doc_id) {
return {};
}
var doc = Docs.findOne({_id:doc_id});
if (doc && doc.content) {
// #1 Later
var editor = Session.get('editor');
if (editor) {
editor.getSession().setValue(doc.content);
}
return doc.content;
} else {
return '';
}
};
When you enter text into the editor div I make a call to Docs.update(doc_id, {$set: {content: text}});, which updates the value in the textarea on each client. All good so far.
editor.getSession().on('change', function(){
var text = editor.getSession().getValue();
Docs.update(doc_id, {$set: {content: text}});
});
What I want to do, for all clients other than the client which made the change, is to subscribe to the change for that doc and call editor.getSession().setContent() with the text which has just been changed, taking the text from the textarea and using it to fill the editor.
I've tried to do this by making that call from the template containing the textarea (as this changes whenever the doc is updated - see #1 above). However, this puts the clients into an infinite loop because changing the value in the editor causes another call to Docs.update.
Obviously this doesn't happen when you render a template, so I'm assuming there's some magic in meteor which can prevent this happening, but I'm not sure how.
Any thoughts?
TIA!
There's a lot to absorb in your question, but if I understand correctly, you might simply be after Deps.autorun:
Deps.autorun(function () {
var doc_id = Session.get('viewing_itemname');
if (!doc_id) {
return {};
}
var doc = Docs.findOne({_id:doc_id});
// do stuff with doc
});
Deps.autorun is really useful in that it will get re-run if any of its
dependencies change. These dependencies are limited to those that are "reactive"
such as Collections and Sessions, or anything that implements the reactive API.
In your case, both Session.get and findOne are reactive so if their values
change at all, Deps.autorun will run the function again.

Collapsible comments in Drupal 7

I'm using the latest Drupal 7.2 core and I have no idea how to solve my problem. I'd like to collapse all nodes comments (there's lots of them) and expose them for the user when he presses 'show comments'. I know it has something to do with the fieldsets (or maybe I'm wrong), but where, what and how ?
Every helpful answer will be appreciated.
Thanks in advance.
I wrote a begging private message to one of the contributors and he posted a working solution for collapsible comments in D7 - http://drupal.org/node/94035#comment-4674734
So i tried a bunch of ways as suggested here.
The thing I ended up doing since I was trying to basically just put all the comments stuff into a collapsible fieldset is outlined here:
Go into the Content Type -> Manage Display.
Create an empty fieldset called something like Comments (You'll need fieldset/fieldcollection modules)
Once you have the group, grab the field_groupname for later use in code.
In your theme's template.php, or whereever you have the render arrays you'll have something like this to basically add the "comments" object into the group fieldset you just created.
function mytheme_preprocess_node(&$vars, $hook){
$tempField = null;
// Copy the comments / comment form into a variable.
$tempField = $vars['content']['comments'];
// Rename some of the labels, use the markup
$tempField['#title'] = "DMS URL";
$tempField['#field_name'] = "field_comments";
$tempField[0]['#markup'] = $vars['content']['comments'];
// Add it into the group (fieldset/group name you copied)
$vars['content']['group_commentsgroup']['field_comments'] = $tempField;
}
This will basically add your comments markup into an empty fieldset/group you created using node's manage display using fieldset/fieldcollection. Also, I was using ajax_comments for this.
This is more of a tip than an answer to your problem, but our website stopped using Drupal comments since they were too basic and moved to use the free service called Disqus
After a looong time of searching For Individual Collapsible comments I found a solution, where you can put your comment replies in an individual collapsible fieldset. :)
Below code in script.js
Include the js in .info file as scripts[] = js/script.js
(function($) {$(function() {
// Hurry up and hide the comments and its replies, if present. In most browsers, this
$('.indented').hide();
// The Comment section will be turned into a toggle to
// open/close the comments
$('.comment').addClass('closed').bind('click', function() {
var $self = $(this),
$form = $self.siblings('.indented'),
speed = 250; // speed of animation, change to suit, larger = slower
if ($self.hasClass('open')) {
$self.addClass('transition').removeClass('open');
$form.hide(speed, function() {
$self.addClass('closed').removeClass('transition');
});
}
else {
$self.addClass('transition').removeClass('closed');
$form.show(speed, function() {
$self.addClass('open').removeClass('transition');
});
}
});
}); })(jQuery);

Resources