Angularjs: not working href when add scope to my directive - href

Here is my html:
<a href="#modal{{screencast.id}}" role="button" class=" btn" data-toggle="modal"
ng-click="fetch_comments(screencast.id)" ng-video url="match_url(screencast.video_url)">Play</a>
My directive:
'use strict';
App.directive('ngVideo', [function () {
return {
restrict: 'A',
scope: { url: '='},
link: function (scope, elem, attrs) {
elem.bind('click', function () {
console.log(scope.url);
});
}
}
}]);
When I refresh page in href="#modal{{screencast.id}}" i have only href="#modal". When I remove scope: { url: '='} from directive it works fine, and href has value of screencast.id.
What i'm doing wrong?

I am going to assume the HTML snippet you posted is placed inside an ng-video element in that case (it is not clear from your message but what you describes seems to indicate this).
When you add scope: { url: '='} to your directive, you create an isolate scope, which means a new scope is created and all the elements inside this directive will live inside this new scope, disconnected from the parent scope. In that case, your {{screencast.id}} binding won't be able to access the screencast object if it was located in the parent scope.
I think for your situation, the best solution would be to remove scope: { url: '='} since you are only using it to read a single attribute and use the attrs parameter instead.
Your link function could look like:
link: function (scope, elem, attrs) {
var urlAttr;
//watch url attribute (we have to wait for the binding to be evaluated, hence the $observe)
attrs.$observe('ngModel', function(value) {
urlAttr = value;
});
elem.bind('click', function () {
if(urlAttr){
console.log(urlAttr);
}
});
}

Related

this.transitionToRoute not working in my controller Ember

I am using a controller to read the value selected on a drop down menu, take in parameters of some input fields and then save the record. It creates the record and takes in the information just fine. My problem lies when I try to transition to another page at the end of the action. I keep getting the error: Cannot read property 'transitionToRoute' of undefined
I am completely stumped. Any ideas?
Here is my controller code:
var teamId;
export default Ember.Controller.extend({
auth: Ember.inject.service(),
actions: {
onSelectEntityType: function(value) {
console.log(value);
teamId = value;
return value;
},
createProcess: function(processName, processDescription) {
var currentID = this.get('auth').getCurrentUser();
let team = this.get('store').peekRecord('team', teamId);
let user = this.get('store').peekRecord('user', currentID);
let process = this.get('store').createRecord('process', {
team: team,
user: user,
name: processName,
description: processDescription
});
process.save().then(function () {
this.transitionToRoute('teams', teamId);
});
}
}
});
Here is the corresponding route:
export default Ember.Route.extend({
auth: Ember.inject.service(),
model: function() {
var currentID = this.get('auth').getCurrentUser();
return this.store.find('user', currentID);
}
});
You should have clear understanding about this keyword in Javascript. The keyword this only depends on how the function was called, not how/when/where it was defined.
function foo() {
console.log(this);
}
// normal function call
foo(); // `this` will refer to `window`
// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`
// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`
Have a look at the MDN documentation to learn more.
You can cache the this in normal variable this and then access inside the call back.
var self = this;
process.save().then(function () {
self.transitionToRoute('teams', teamId);
});
ECMASCript 6 introduced arrow functions whose this is lexically scoped. Here, this is looked up in scope just like a normal variable.
process.save().then(() => {
this.transitionToRoute('teams', teamId);
});

Getting the name of a function provided to an Ember `action` helper

I'm assuming this isn't possible, but wanted to see if anyone knew any better.
With ES6, you can get the name of a function. For instance:
function foo() { return true; }
function bar() { return true; }
const functionContainer = foo;
foo.name; // 'foo'
bar.name; // 'bar'
functionContainer.name; // 'foo'
In Ember, you can pass an action into an action helper. For instance:
export default Ember.Component.extend({
actions: {
bar() {
return true;
}
}
});
And the template:
{{foo-component foo=(action "bar")}}
Within foo-component, is there some way to do this:
export default Ember.Component.extend({
doFoo: Ember.on('didRecieveAttrs', function() {
console.log(this.attrs.foo.name); // 'bar'
})
});
When I try, I just get a blank string. This makes sense, since it looks like the bar action is getting wrapped in a nameless function by ember-metal.
Anyone know of a way to grab that name? It would make a huge difference for a project I'm working on.
Nope, you can't do exactly what you want < insert technical discussion about closures here >, but you can kinda fake it by just adding another param to your component, like so:
{{foo-component foo=(action "bar") actionName="bar"}}
then in your component.js you can access
this.attrs.actionName // "bar"

Meteor.js - Calling a template helper within template rendered

I'm using Meteor 1.0.
I have a Template.*name*.rendered function that makes a number of calculations. At the end of the calculations, I would like the output to make its way into a Template.*name*.helpers so I can use it in the corresponding html page.
Here's a simplified version of the code:
Template.myTemplate.rendered = function () {
var x = Math.random();
Template.otherTemplate.helpers({
randomNum: x
});
}
When I call {{randomNum}} in otherTemplate, nothing happens.
I have also tried putting the Template.*name*.helpers outside of Template.*name*.rendered, in which case, I get the error:
Uncaught ReferenceError: x is not defined
Thoughts?
This isn't really the right way of going about things as the way Meteor works is by compiling templates before the application starts, rather than at run-time. Whilst something along these lines may be possible (for example by using Template.registerHelper), it would be much better to set a reactive variable to a specific value in the rendered callback and have the helper set to return that instead:
Session.setDefault('randomNum', 0);
Template.myTemplate.rendered = function () {
Session.set('randomNum', Math.random());
}
Template.otherTemplate.helpers({
randomNum: Session.get('randomNum')
});
If you'd rather use a private variable for the randomNum, have a look at ReactiveVar. It could be any reactive data source and it would work.
You used to create helpers as an object of the template but since Meteor has deprecated that you now have to create the helpers within the helper function.
Now in order to call the helper via javascript you must use this function
Template.*TemplateName*.__helpers.get('*HelperName*')(*Params*);
Its a pretty simple way of doing this and it keeps the functions out of the global scope so its pretty clean.
Here is an example of how I am using this
~~~
Template.home.events({
'click .pair': function(event) {
var _this = $(event.currentTarget);
Template.home.__helpers.get('pairDevice')(_this);
}
});
Template.home.helpers({
'devices' : function() {
return Session.get('devices');
},
'pairDevice' : function(elm) {
elm.fadeOut();
$('.home-page').addClass('paired');
var deviceList = [
{
'name' : 'Patrick\'s Phone',
'UUID' : '234123,4n123k4nc1l2k3n4 l1k23n4l12k3nc4l12'
},
{
'name' : 'Mike\'s Phone',
'UUID' : '734k23k4l2k34l2k34l2k34l2k3m'
},
{
'name' : 'Edgar\'s Phone',
'UUID' : '567k56l7k4l56k7l5k46l74k56l74k5'
}
];
Session.set('devices', deviceList);
}
});
~~~

knockoutjs - custom template is binded with parent content

I have a problem using knockoutjs with custom template bindings.
Suppose I have a HTML body like this:
<div id="1">
<div data-bind="template:{name: '2', data: data}"></div>
</div>
<div id="2">
<h3 data-bind="text: caption"></h3>
</div>
JS code looks like this:
var ViewModel2 = function () {
this.caption = ko.observable("Caption");
}
var ViewModel1 = function () {
this.data = new ViewModel2();
}
ko.applyBindings(new ViewModel1(), document.getElementById("1"));
If we test this code, everything will work just fine;
See JSFiddle example: http://jsfiddle.net/4eTWW/33/
Now suppose we want to make our custom template binding. We'll use 'templatex' binding instead of 'template'.
In HTML we need to change just one line:
<div data-bind="templatex:{name: '2', data: data}"></div>
Next, let's add custom template binding to JS:
/*Custom binding*/
ko.bindingHandlers.templatex = {
init: function (element) {
ko.bindingHandlers.template.init.apply(this, arguments);
},
update: ko.bindingHandlers.template.update
}
See: http://jsfiddle.net/4eTWW/35/
But in this case we have an error, saying that it can't find 'caption' in the model.
Now let's add template {} to html bindings:
<div data-bind="template: {}, templatex:{name: '2', data: data}"></div>
See: http://jsfiddle.net/4eTWW/36/
And now everything works just fine.
It seems that while binding parent div it can't determine that child div is a template.
So how can I mark it as a template in my custom template binder?
Thanks.
You have wrong update handler, change to this:
ko.bindingHandlers.templatex= {
init: function(element) {
// do things
return ko.bindingHandlers.template.init.apply(this, arguments);
},
update: function(element) {
return ko.bindingHandlers.template.update.apply(this, arguments);
}
}
Here is working fiddle: http://jsfiddle.net/vyshniakov/4eTWW/39/
I don't think you can use a custom binding to create a new template engine. You need to register your custom engine with ko.setTemplateEngine().
From the knockoutjs source:
If you want to make a custom template engine,
[1] Inherit from the ko.templateEngine class (like ko.nativeTemplateEngine does)
[2] Override 'renderTemplateSource', supplying a function with this signature:
function (templateSource, bindingContext, options) {
// - templateSource.text() is the text of the template you should render
// - bindingContext.$data is the data you should pass into the template
// - you might also want to make bindingContext.$parent, bindingContext.$parents,
// and bindingContext.$root available in the template too
// - options gives you access to any other properties set on "data-bind: { template: options }"
//
// Return value: an array of DOM nodes
}
[3] Override 'createJavaScriptEvaluatorBlock', supplying a function with this signature:
function (script) {
// Return value: Whatever syntax means "Evaluate the JavaScript statement 'script' and output the result"
// For example, the jquery.tmpl template engine converts 'someScript' to '${ someScript }'
}
This is only necessary if you want to allow data-bind attributes to reference arbitrary template variables.
If you don't want to allow that, you can set the property 'allowTemplateRewriting' to false (like ko.nativeTemplateEngine does)
and then you don't need to override 'createJavaScriptEvaluatorBlock'.
Example: http://jsfiddle.net/6pStz/ (see Note 7 on this page)

dust.js losing 'this' context in handlers?

I have a [seemingly] trivial dust.js template. The context object I am using to render the template contains a handler which references another item in the context object. I also include a toString handler, which also references another item in the context object.
Template:
{error}
<pre>
{#error.getStackTrace}
{.}{~n}
{/error.getStackTrace}
</pre>
Context:
{
error: {
st: ['a','b','c'],
msg: 'This is an error message',
getStackTrace: function () {
return this.st;
},
toString: function () {
return this.msg;
}
}
}
Rendered:
This is an error message<pre></pre>
If I reference {#error.st} directly, it renders correctly:
This is an error message<pre>a
b
c
</pre>
If I inspect 'this' inside of the getStackTrace() handler, it is pointing back to DOMWindow. It is interesting, however, that invoking toString() implicitly, it is scoped correctly. If I explicitly invoke toString() {error.toString}, then the scope jumps back to DOMWindow.
The only reason this is a problem, (why I cannot access error.st directly) is because the st array is actually stored in a Qooxdoo property, and I only have access to the generated getter. The above example mimics the actual object as simply as I can.
Is this a bug in dust.js? Is it losing the correct scope in handlers? Or am I missing something in the dust.js docs to retain scope?
you could use it in this way:
{
error: {
st: 'a,b,d',
msg: 'This is an error message',
getStackTrace: function (chunk, context) {
return context.current().error.st;
},
toString: function () {
return this.msg;
}
}
}
this is Javascript isn't always obvious, especially when you are returning functions.
When Dust resolves references like {error.st} which is a function. It calls that function, but it does not set a scope for it; so it defaults to the global scope which in your browser is window.
Look at this line: https://github.com/akdubya/dustjs/blob/master/lib/dust.js#L319
Here is what is sorta happening:
var current_context = {
st: 'a,b,d',
msg: 'This is an error message',
getStackTrace: function (chunk, context) {
return error.st;
},
toString: function () {
return this.msg;
}
}
current_context.st(); // outputs correctly
var elem = current_context.st; // here is your reference {.}
elem(); // Dust tries to resolve your reference but it doesn't set the scope
elem.call(current_context); // if we pass the scope you'll get what you want.
Is this a bug in Dust? Probably not since you have the context via context.current().
Does it make sense for this to point to window. No, but when you use Dust on the server side I imagine, we'll have a better use for this.