The following bound {{if}} statement is not reevaluated when the object 'model' it is bound to changes. This is contrary to my expectation and what I thought was the purpose of binding an if statement to an object. Am I doing something wrong?
if-data.js:
Handlebars.registerHelper("ifData", function(property, fn)
{
var context = (fn.contexts && fn.contexts[0]) || this;
var args = [property];
var canAction = function(can_args)
{
alert('I was called for '+can_args[0].get('id'));
return true;
};
// Resolve actual values for all params to pass to the conditional callback
var normalizer = function() {
return Ember.Handlebars.resolveParams(context, args, fn);
};
return Ember.Handlebars.bind.call(context, 'content', fn, true, canAction, normalizer, args);
});
show.hbs:
{{#ifData model }}
<h1> Showme </h1>
{{/ifData}}
When testing I am updating the bound obejct using this in the console:
App.__container__.lookup('store:main').find('post',1).then(function(model){
model.set('title','mydream20');
model.save();
});
Related
Quick and shortly I have following problem:
I have following two actions within a component in Ember:
createData: function(user) {
let collection = [];
for (let i = 0; i < user.posts.length; i++) {
let data = this.send('createSingleData',user.posts[i], user, 'post');
console.log(data);
collection.push(data);
}
return collection;
},
createSingleData: function(data, user, type) {
let entitySkeleton = {
name: data.place.name,
belongsTo: user.id,
position: {
data.place.location.longitude,
data.place.location.latitude
}
};
console.log(entitySkeleton);
return entitySkeleton;
}
the first log - within createSingleData, right before returning the logged value - writes the entitySkeleton as Object into the console - as expected.
However, the console.log(data) - within createData - writes 'undefined' to the console.
Is there any aspect of asynchrounosity I didn't respect?
P.S.:
I also logged any paramater within createSingleData, they are all set properly.
The variable collection also only gets pushed 'undefined'.
You cannot return the value from action, instead you can set property from the action.
how to return values from actions in emberjs
actions: {
PrintSomething: function() {
let obj = [{a: 'raj'}, {a: 'Prudvi'}, {a : 'thimappa'}]
console.log('before', obj);
this.send('returnSomething', obj);
console.log('after calling action', this.get('returnvalue'));
},
returnSomething: function(obj) {
obj.push({a: 'FSDFSDF'})
var data = obj;
this.set('returnvalue', data);
}
}
I have two questions regarding "beforeRemote" method of loopback-
How do I get hold of model methods inside beforeRemote method? I mean inside beforeRemote I want to invoke (lets say) "upsert" method of the model.
How do I return invocation from beforeRemote? By return I mean instead of hitting the target invoked method the execution will return from beforeRemote method.
My code -
Installation.beforeRemote("create", function (context, result, next) {
var data = context.req.body;
console.log("ImEI" + data.imei);
data.vendor = "jahid";
var self = this;
var filter = {where: {imei: data.imei}};
//the self here point to global object. but i want self to point to model
self.findOne(filter, function (err, result) {
if (result) {
data.id = result.id;
self.upsert(data, function(err, result){
if(err){
next(err);
} else if(result) {
//here i want to send a valid response back to client with 200 and body as my model.
next(data);
}
});
return;
}
next();
});
});
You have access to the Installation model from the module.exports declaration:
module.exports = function(Installation) {
...
Installation.upsert...
...
}
You have access to the response object from the context object. So you could just respond with something like context.res.send('hello world') and not call next().
I'm trying to modify the behaviour of pushPayload in the RESTSerializer. However the function is never called.
pushPayload: function(store, payload) {
console.log('pushPayload');
payload = this.normalizePayload(payload);
for (var prop in payload) {
var typeName = this.typeForRoot(prop),
type = store.modelFor(typeName),
typeSerializer = store.serializerFor(type);
/*jshint loopfunc:true*/
var normalizedArray = map.call(Ember.makeArray(payload[prop]), function(hash) {
return typeSerializer.normalize(type, hash, prop);
}, this);
store.pushMany(typeName, normalizedArray);
}
},
normalizePayload: function(payload) {
console.log('normalize');
return payload;
},
This will output only:
normalize
I really have no idea what's going on. I literraly copied from the master both methods. There is no typo and if normalizePayload is called pushPayload should be called also!
normalizePayload is called from both extractSingle (store.find('foo', 1);), store.extractArray (store.find('foo');) and pushPayload (store.pushPayload('foo', obj);).
You need to actually call pushPayload on the store with the type of the serializer defined. Additionally be careful, map is defined earlier in the document:
var map = Ember.ArrayPolyfills.map;
App.FooSerializer = DS.RESTSerializer.extend({
pushPayload: function(store, payload) {
console.log('pushPayload');
payload = this.normalizePayload(payload);
for (var prop in payload) {
var typeName = this.typeForRoot(prop),
type = store.modelFor(typeName),
typeSerializer = store.serializerFor(type);
/*jshint loopfunc:true*/
var normalizedArray = map.call(Ember.makeArray(payload[prop]), function(hash) {
return typeSerializer.normalize(type, hash, prop);
}, this);
store.pushMany(typeName, normalizedArray);
}
},
});
http://emberjs.jsbin.com/OxIDiVU/730/edit
how to return some value from actions??
I tried this:
var t = this.send("someAction", params);
...
actions:{
someAction: function(){
return "someValue";
}
}
actions don't return values, only true/false/undefined to allow bubbling. define a function.
Ember code:
send: function(actionName) {
var args = [].slice.call(arguments, 1), target;
if (this._actions && this._actions[actionName]) {
if (this._actions[actionName].apply(this, args) === true) {
// handler returned true, so this action will bubble
} else {
return;
}
} else if (this.deprecatedSend && this.deprecatedSendHandles && this.deprecatedSendHandles(actionName)) {
if (this.deprecatedSend.apply(this, [].slice.call(arguments)) === true) {
// handler return true, so this action will bubble
} else {
return;
}
}
if (target = get(this, 'target')) {
Ember.assert("The `target` for " + this + " (" + target + ") does not have a `send` method", typeof target.send === 'function');
target.send.apply(target, arguments);
}
}
I had the same question. My first solution was to have the action put the return value in a certain property, and then get the property value from the calling function.
Now, when I need a return value from an action, I define the function that should be able to return a value seperately, and use it in an action if needed.
App.Controller = Ember.Controller.extend({
functionToReturnValue: function(param1, param2) {
// do some calculation
return value;
},
});
If you need the value from the same controller:
var value = this.get("functionToReturnValue").call(this, param1, param2);
From another controller:
var controller = this.get("controller"); // from view, [needs] or whatever
var value = controller.get("functionToReturnValue").call(controller, param1, param2); // from other controller
The first argument of the call() method needs to be the same object that you are running the return function of; it sets the context for the this reference. Otherwise the function will be retrieved from the object and ran from the current this context. By defining value-returning functions like so, you can make models do nice stuff.
Update I just found this function in the API that seems to do exactly this: http://emberjs.com/api/#method_tryInvoke
Look this example:
let t = this.actions.someAction.call(this, params);
Try
var t = this.send("someAction", params);
instead of
vat r = this.send("someAction", params);
Just use #set for set value which you want to return
actions:{
someAction: function(){
// return "someValue";
this.set('var', someValue);
}
}
I'm having a difficult time returning data from a module using RequireJS and Knockout to populate my markup for my single page app. Knockout can't seem to find my data binding observables.
I'm trying to keep each view in a separate js file, but I'm failing to identify where I've gone wrong. Here's what I have so far:
/app/app.js
define(function(require) {
require('simrou');
var $ = require('jQuery'),
ko = require('knockout'),
videoView = require('videoView');
var init = function() {
var viewModel = function() {
var self = this;
self.currentPage = ko.observable();
self.videoView = new videoView();
}
var view = new viewModel();
ko.applyBindings( view );
_router = new Simrou({
'/video/:id': [ view.videoView.getVideo ]
});
_router.start();
};
return {
init: init
};
});
/app/videoView.js
define(function(require) {
"use strict";
var $ = require('jQuery'),
ko = require('knockout');
return function() {
var self = this;
self.currentPage = ko.observable( 'showVideo' );
self.currentVideo = ko.observable();
self.videoData = ko.observableArray([]);
self.videoList = ko.observableArray([]);
var getVideo = function( event, params ) {
// ajax pseudo code
$.ajax({});
self.videoData( dataFromAjaxCall );
}
return {
getVideo: getVideo
};
};
});
index.html
When I browse to /#/video/14 I receive the following error:
Uncaught ReferenceError: Unable to parse bindings.
Bindings value: attr: { 'data-video-id': videoData().id }
Message: videoData is not defined
Here's the markup:
<section id="showVideo" data-bind="fadeVisible: currentPage()=='showVideo', with: $root">
<div class="video" data-bind="attr: { 'data-video-id': videoData().id }></div>
</section>
Like I said, I'm trying to keep each view separated, but I would love some enlightenment on what I'm doing wrong, or if this is even possible? Is there a better more efficient way?
videoData is a property of $root.videoView, not of the root model (the one you passed to applyBindings). It's also an observableArray, so videoData() is just a plain array and even if you get the context right, you won't be able to access its id property, since, being an array, it doesn't have.named properties.