Pass result of a function back to itself in Ember.js controller - javascript

I have a function that does what I want it to do using lodash and vanilla javascript. I pass it a value, it checks to see if that value is already mapped, and then it checks to see if the value has specific child properties. If it does, it passes the the child property through the same function.
I'm trying to do essentially the same thing in an ember app, but the function is a property in a controller. When I try to reference the function name, I get an error: "Uncaught ReferenceError: collectHeaders is not a function". How can I pass the result of "collectHeaders(child)" back to the function?
Just lodash & javascript where it works:
function collectHeaders(parent) {
var firstChild = parent.children ? parent.children[0] : {};
if (firstChild.section_type && firstChild.section_value) {
_.forEach(parent.children, function(child) {
collectHeaders(child)
});
} else if (parent.children) {
// more code
}
}
Ember.app controller with lodash:
var mapping = {};
var CompareController = Ember.ObjectController.extend({
collectHeaders: function(parent) {
var firstChild = parent.children ? parent.children[0] : {};
if (firstChild.section_type && firstChild.section_value) {
_.forEach(parent.children, function(child) {
collectHeaders(child);
});
} else if (parent.children) {
// more code
}
},
});
export default CompareController;

Your code is out of scope, your previous function was global
collectHeaders: function(parent) {
var self = this;
var firstChild = parent.children ? parent.children[0] : {};
if (firstChild.section_type && firstChild.section_value) {
_.forEach(parent.children, function(child) {
self.collectHeaders(child);
});
} else if (parent.children) {
// more code
}
},
});

Related

Javascript & knockoutjs: how to refactor the following code to be able to access the properties outside the function

Im struggling to find a way to get the properties Override & Justification available outside of the function. The code is:
self.CasOverridesViewModel = ko.observable(self.CasOverridesViewModel);
var hasOverrides = typeof self.CasOverridesViewModel === typeof(Function);
if (hasOverrides) {
self.setupOverrides = function() {
var extendViewModel = function(obj, extend) {
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
extend(obj[property]);
}
}
};
extendViewModel(self.CasOverridesViewModel(), function(item) {
item.isOverrideFilledIn = ko.computed( function() {
var result = false;
if (!!item.Override()) {
result = true;
}
return result;
});
if (item) {
item.isJustificationMissing = ko.computed(function() {
var override = item.Override();
var result = false;
if (!!override) {
result = !item.hasAtleastNineWords();
}
return result;
});
item.hasAtleastNineWords = ko.computed(function() {
var justification = item.Justification(),
moreThanNineWords = false;
if (justification != null) {
moreThanNineWords = justification.trim().split(/\s+/).length > 9;
}
return moreThanNineWords;
});
item.isValid = ko.computed(function() {
return (!item.isJustificationMissing());
});
}
});
}();
}
I've tried it by setting up a global variable like:
var item;
or
var obj;
if(hasOverrides) {...
So the thing that gets me the most that im not able to grasp how the connection is made
between the underlying model CasOverridesviewModel. As i assumed that self.CasOverridesViewModel.Override() would be able to fetch the data that is written on the screen.
Another try i did was var override = ko.observable(self.CasOverridesViewModel.Override()), which led to js typeError as you cannot read from an undefined object.
So if anyone is able to give me some guidance on how to get the fields from an input field available outside of this function. It would be deeply appreciated.
If I need to clarify some aspects do not hesitate to ask.
The upmost gratitude!
not sure how far outside you wanted to go with your variable but if you just define your global var at root level but only add to it at the moment your inner variable gets a value, you won't get the error of setting undefined.
var root = {
override: ko.observable()
};
root.override.subscribe((val) => console.log(val));
var ViewModel = function () {
var self = this;
self.override = ko.observable();
self.override.subscribe((val) => root.override(val));
self.load = function () {
self.override(true);
};
self.load();
};
ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

Vue optionMergeStrategies Methods has no access to 'this' keyword

I am trying to build a plugin for Vue.
My plugin has a custom method caller customMethod for every component, I want it to run on after the page is mounted/created.
In a simple way, this is working as I want but I am having trouble accessing this inside customMethod.
It logs 'undefined' when I am trying to console.log(this).
so how can I access this inside my customMethod ?
var defaultParms = Object.freeze({
start : function(){},
leave : function(){},
});
const myPlugin = {
install(Vue, options = []) {
var ref = Vue.util;
var extend = ref.extend;
var assets = Object.create(null);
extend(assets, defaultParms);
Vue.options.customMethod = assets;
// set option merge strategy
var strats = Vue.config.optionMergeStrategies;
if (strats) {
strats.customMethod = (parent, child, vm)=>{
if (!child) return parent;
if (!parent) return child;
var ret = Object.create(null);
extend(ret, parent);
for (var key in child) {
ret[key] = child[key];
}
return ret
};
}
Vue.mixin({
customMethod:{
start: function(){
console.log('hi') // log 'hi'
console.log(this.$appName) // log 'undefined'
}
},
created: function () {
if(this.$options.customMethod){
this.$options.customMethod.start && this.$options.customMethod.start();
}
}
});
Vue.prototype.$appName = 'vikash';
}
}
Vue.use(myPlugin)
new Vue().$mount('#app')
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>
This is part of how the context this works in JS. You need to set it with bind, call or apply:
this.$options.customMethod.start.call(this)

How to create methods with a loop in jquery/javascript

I'm having problems trying to register some methods I've created in a loop inside an object.
what I'm having is this:
var scriptList = {
components : [
'all'
],
modules : [
'one',
'two',
'three'
]
}
function interface() {
var scope = this;
jQuery.each(scriptList, function(key, value) {
jQuery.each(value, function (index, name) {
var hookValue = 'hook_'+name;
scope.name = function(){
window[hookValue] = jQuery('.js-'+name);
loadAndUse(window[hookValue],key+'/'+name);
}
if(key === 'modules'){
scope.name();
}
});
});
}
var ui = new interface();
It's working and do its job, but I want to be able to reach every method I've created through the loop in this way: console.log(ui.one());
And I don't how to do something like that since if I do this:
function interface() {
var scope = this;
scope.one = function(){ console.log('one'); }
scope.two = function(){ console.log('two'); }
scope.three = function(){ console.log('three'); }
}
then I can access through console.log(ui.one()); with no problem...
What am I missing? Is there some way I don't know on registering the method when you iterate them?
scope.name refers the the name property on scope. If you want to access a property based on a string value, you need to use square bracket notation:
scope[name] = function(){
window[hookValue] = jQuery('.js-'+name);
loadAndUse(window[hookValue],key+'/'+name);
}

Call function in parent's parent from inside jquery's .each

I've created a 'class' in javascript called QuoteProductService(), see below.
I've added two functions to the prototype and now, I'm trying to call one of the functions (getQuoteProductFromArray) from within a jquery $.each inside the other function (getFakeQuoteProducts). This doesn't work. I've tried adding 'this.', but this also does not work, because 'this' inside the .each refers to the current element in the loop.
How should I do this ?
function QuoteProductService() {
}
QuoteProductService.prototype.getQuoteProductFromArray = function(quoteproductarray, quoteproductid){
var founditem=null;
// do stuff
return founditem;
}
QuoteProductService.prototype.getFakeQuoteProducts = function(){
// do something to fill the mappedQuoteProducts array
$.each(mappedQuoteProducts, function (index, quoteproduct) {
if (quoteproduct!=-null) {
if (quoteproduct.parentid != "") {
// this is where it goes wrong :
var parent = getQuoteProductFromArray(mappedQuoteProducts, quoteproduct.parentid);
if (parent != null) {
parent.attachChild(quoteproduct);
}
}
}
});
}
Save a reference to your QuoteProductService instance before calling each
QuoteProductService.prototype.getFakeQuoteProducts = function(){
var _this = this;
// do something to fill the mappedQuoteProducts array
$.each(mappedQuoteProducts, function (index, quoteproduct) {
if (quoteproduct!=-null) {
if (quoteproduct.parentid != "") {
// this is where it goes wrong :
var parent = _this.getQuoteProductFromFlatArray(mappedQuoteProducts, quoteproduct.parentid);
if (parent != null) {
parent.attachChild(quoteproduct);
}
}
}
});
}
Add var self = this; to the beginning of the getFakeQuoteProducts function. Then call getQuoteProductFromFlatArray like this: self.getQuoteProductFromFlatArray.
First of all you provided wrong method name - getQuoteProductFromFlatArray instead of getQuoteProductFromArray. Secondly in JS you must provide scope for instance methods.
Easiest way to achieve this is to store this reference into some other, private variable. See the example below.
function QuoteProductService() {
}
QuoteProductService.prototype.getQuoteProductFromArray = function(quoteproductarray, quoteproductid){
var founditem=null;
// do stuff
return founditem;
}
QuoteProductService.prototype.getFakeQuoteProducts = function(){
var me = this; // store this into me
// do something to fill the mappedQuoteProducts array
$.each(mappedQuoteProducts, function (index, quoteproduct) {
// this === me will return false
if (quoteproduct!=-null) {
if (quoteproduct.parentid != "") {
// this is where it goes wrong :
var parent = me.getQuoteProductFromArray(mappedQuoteProducts, quoteproduct.parentid);
if (parent != null) {
parent.attachChild(quoteproduct);
}
}
}
});
}

How to create a javascript library using a closure

I have written some javascript that I would to encapsulate in a closure so I can use it elsewhere. I would like do do this similar to the way jQuery has done it. I would like to be able to pass in an id to my closure and invoke some functions on it, while setting some options. Similar to this:
<script type="text/javascript">
_snr("#canvas").draw({
imageSrc : someImage.png
});
</script>
I have read a lot of different posts on how to use a closure to do this but am still struggling with the concept. Here is where I left off:
_snr = {};
(function (_snr) {
function merge(root){
for ( var i = 1; i < arguments.length; i++ )
for ( var key in arguments[i] )
root[key] = arguments[i][key];
return root;
}
_snr.draw = function (options) {
var defaults = {
canvasId : 'canvas',
imageSrc : 'images/someimage.png'
}
var options = merge(defaults, options)
return this.each(function() {
//More functions here
});
};
_snr.erase = function () {};
})(_snr);
When ever I try to call the draw function like the first code section above, I get the following error, '_snr is not a function'. Where am I going wrong here?
EDIT
Here is what I ended up doing:
function _snr(id) {
// About object is returned if there is no 'id' parameter
var about = {
Version: 0.2,
Author: "ferics2",
Created: "Summer 2011",
Updated: "3 September 2012"
};
if (id) {
if (window === this) {
return new _snr(id);
}
this.e = document.getElementById(id);
return this;
} else {
// No 'id' parameter was given, return the 'about' object
return about;
}
};
_snr.prototype = (function(){
var merge = function(root) {
for ( var i = 1; i < arguments.length; i++) {
for ( var key in arguments[i] ) {
root[key] = arguments[i][key];
}
}
return root;
};
return {
draw: function(options) {
var defaults = {
canvasId : 'canvas',
imageSrc : 'images/someimage.png'
};
options = merge(defaults, options);
return this;
},
erase: function() {
return this;
}
};
})();
I can now call:
<script type="text/javascript">
_snr("#canvas").draw({
imageSrc : someImage.png
});
</script>
Because you declared _snr as an object and not a function. Functions can have properties and methods, so there's various ways to achieve what you want, for example one of them would be say...
_snr = function(tag) {
this.tag = tag;
}
_snr.foo = function() {
//Code goes here
}
You can also pass the outer context into a closure to hide your variables from accidentally polluting the global namespace, so like...
(function(global) {
var _snr = function(tag) {
this.tag = tag;
}
_snr.foo = function() {
//Code goes here
}
//export the function to the window context:
global._snr = _snr;
})(window);
window._snr('#tag').foo('wat');
Happy coding.
Because your _snr is an object, not a function. You have to call it like this:
_snr.draw({
canvasId: '#canvas',
imageSrc: 'someImage.png'
});
When you do _snr('#canvas') that is a function call which is why you're getting that error. _snr is an object with some methods attached to it such as draw() and erase(). The reason jQuery is able to pass arguments into the $ is because they return the $ as a function object which is why we're able to pass it various selectors as arguments.
You are going wrong at the first line _snr = {}
It needs to be
_snr = function(){
selector = arguments[0]||false;
//snr init on dom object code
return _snrChild;
}
Im on a mobile phone but when im on a pc I will maybe fix the whole code c:
Here you have a snr object and that has erase and draw methods. What you intend to do is to write a _snr function which will get an id and return a wrapper object. That returned object should have erase and draw methods. so you can do
var returnedObject = _snr("my_id");
returnedObject.draw("image.png");

Categories