Object initialize different in Angular directive than controller? - object

I've have run into an issue with object initialization differing whether the code is in a controller vs a directive link function. In the example code below, the "this" parameter being passed in the
prop: new Object(this)
is a legit Object constructor when the code is run in the controller but is undefined when run in the directive. Why the difference in execution of the same code?
myapp.directive("myDir",function()
{
var myDir = {
link: function(scope,element,attrs)
{
var obj;
obj = new Object({
prop: new Object(this)
});
}
}
return myDir;
}
myapp.controller("MyCtrl",function($scope)
{
var obj;
obj = new Object({
prop: new Object(this)
});
}

I think your use of "this" in the declarations is the problem. Read up on How does the "this" keyword work? to make sure you understand how it works.
To me it looks like "this" will probably be set to the "myDir" variable in the directive, and the window object in the controller.

Related

Error: Argument "data" is not a valid Document. Input is not a plain JavaScript object

I am getting the error
Error: Argument "data" is not a valid Document. Input is not a plain
JavaScript object.
when updating a document, using firebase admin SDK. Here the Typescript code.
var myDoc = new MyDoc();
myDoc.Public.Name = "Jonh Doe" //setup up content
admin.firestore()
.collection('MyDocs')
.doc("Id1")
.set(myDoc);
I did something similar:
var myDoc = <MyDoc> {
Public: {
Name: "Jonh Doe"
}
}
It is semantically the same, I just think it is a bit cleaner.
In case some else bump into the same issue, the solution is to simple use Json to instantiate the object, like this:
var myDoc = {
Public: {
Name: "Jonh Doe"
}
} as MyDoc; //keep type to still get typescript compiler validations
I had same problem, in my case I'd forgot to add Content-Type:application/json to my header when sending request, and then the object was treated as string and I got that error.
You can recreate js object via; {...__data}
return refDB.set({...__data}).then((newData) => {
})

Calling function with callback defined as string

var method = 'serviceName.MethodName'
I Just want to call it like
serviceName.methodName(function(output callback){
});
Is there any approach to call it.thanks
There are two methods that I can think of now.
JS eval
You can use the javascript eval function to convert any string into code snippet like below. Although eval is a quick solution but should not be used unless you dont have any other option by your side.
var method = 'UserService.getData';
eval(method)();
Factory pattern
Use a below pattern to get the service
You would need to define the services in such a manner that you can access them using a pattern.
var Services = {
// UserService and AccountsService are again objects having some callable functions.
UserService : {getData: function(){}, getAge: function(){}},
AccountsService : {getData: function(){}, getAge: function(){}},
// getService is the heart of the code which will get you the required service depending on the string paramter you pass.
getService : function(serviceName){
var service = '';
switch(serviceName){
case 'User':
service = this.UserService;
break;
case 'Accounts':
service = this.AccountsService;
break;
}
return service;
}
}
You can use get the required service with below code
Services.getService('User')
I'm not aware of any way you can resolve the serviceName part of that string to an object, without using eval. So obviously you need to be extremely careful.
Perhaps:
if (method.match(/^[a-zA-Z0-9_]+\.[a-zA-Z0-9_]+$/) {
var servicePart = eval(method.split('.')[0]);
var methodPart = method.split('.')[1];
servicePart[methodPart](...)
}
There are two separate problems in your question:
How to access object property by property name (string)?
How to access object by it's name (string)?
Regarding the first problem - it is easy to access object property by string using the following notation:
const myObject = {
myProp: 1,
};
console.log(myObject['myProp']);
And regarding the second problem - it depends on what serviceName is:
if it is a property of some other object, then use someObject['serviceName']['MethodName']
if it is a local variable, consider using a Map (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) to associate strings with objects;

Does assigning module.exports to a separate object waste memory

There are two basic ways that I see Node modules being written. The first setting each function or variable you want to export to its own property on module.exports:
module.exports.foo = function () {
...
}
And the second is creating a new object that has the properties you want to export, and assigning module.exports to that at the end of the file:
var FooObject = {
foo: function () {
...
}
};
...
module.exports = FooObject;
A third thing that I sometimes see is setting module.exports to an object which has all the properties you want to export, but for the purposes of this discussion, that's equivalent to the first method I mentioned:
module.exports = {
foo: function () {
...
}
}
Are we wasting memory by doing it the second way (creating an object and assigning module.exports to that)? I always thought that since all assignment is a reference, a new object should be created when you do module.exports = {...} so these two would be equivalent. Is that not the case?
The last two examples are equivalent. The only difference is that the second one is setting the object by name and the third is setting it by the object literal.

How to observe all object property changes?

For arrays I know you can do something like this:
function() {
}.observes("array.#each")
What I did was convert the object into an array and observe the properties with a #each, but is there a better way to observe object all property changes without converting it into an array?
You can observe isDirty to see if any of the object's values have been modified since last save (if you are using Ember Data).
Alternatively you can pass a comma separated list of properties to observes. This might be long if you have a lot of properties on your object, but will work.
A third approach could be to override setUnknownProperty() and set a property, a 'dirty flag' (or perform any action you may want in there.
There's also an old SO post that gives the following answer:
App.WatchedObject = Ember.Object.extend({
firstProp: null,
secondProp: "bar",
init: function(){
this._super();
var self = this;
Ember.keys(this).forEach(function(key){
if(Ember.typeOf(self.get(key)) !== 'function'){
self.addObserver(key, function(){
console.log(self.get(key));
});
}
});
}
});
You could probably split this out into a Mixin to keep your code DRY.
probably you could create something like a blabbermouth mixin and override the set method to get notified of property changes:
App.BlabbermouthMixin = Ember.Mixin.create({
set: function(keyName, value) {
this.set('updatedProperty', keyName);
this._super(keyName, value);
}
});
and observe the updatedProperty property?
You can get a list of properties in an object and apply them to a new property:
attrs = Ember.keys(observedObject);
var c = Ember.computed(function() {
// Do stuff when something changes
})
Ember.defineProperty(target, propertyName, c.property.apply(c, attrs));
Here is a working jsbin. Creating an observer instead of a property should be possible using a similar approach.

How can I break this code up into two RequireJs modules

I've created the code below to dynamically load 2 buttons into an element with an ID of masthead. Then a function called showMenus runs when each button is clicked, running some jQuery animations. Everything is wrapped inside of a RequireJS module.
The code works fine as is but I'm thinking it may be better to break it up into two separate RequireJS modules/files: one that loads the buttons on the page and another one that runs the showMenus function. I did refer to the RequireJS API docs but couldn't find an answer.
Any help is appreciated...thanks in advance!
require(['jquery'], function ($) {
var header = document.getElementById("masthead"),
$navMenu = $("#site-navigation-list"),
$searchBox = $("#searchform"),
menuButton = document.createElement("div"),
searchButton = document.createElement("div"),
showMenus;
$(menuButton).attr("id", "menu");
$(searchButton).attr("id", "search");
header.appendChild(searchButton);
header.appendChild(menuButton);
// break the code below into its on RequireJS module?
showMenus = function(btn,el) {
$(btn).click(function() {
if (el.is(":visible") ) {
el.slideUp({
complete:function(){
$(this).css("display","");
}
});
} else {
el.slideDown();
}
});
};
showMenus(menuButton, $navMenu);
showMenus(searchButton, $searchBox);
});
What follows is only my opinion, but you might find it useful.
It might help to think in terms of things that your app is made of, and then maybe they are candidates for modules. So in your example, a 'masthead' seems to be a thing that you are interested in.
So using RequireJS, we can create a new module representing a generic masthead:
// Masthead module
define(['jquery'], function ($) {
function showMenus (btn, el) {
function toggle (el) {
if (el.is(":visible")) {
el.slideUp({
complete:function(){
$(this).css("display","");
}
});
} else {
el.slideDown();
}
}
$(btn).click(function() {
toggle(el);
});
}
// A Masthead is an object that encapsulates a masthead DOM element.
// This is a constructor function.
function Masthead (mastheadElement) {
// 'this' is the masthead object that is created with the 'new'
// keyword in your application code.
// We save a reference to the jQuerified version of mastheadElement.
// So mastheadElement can be a DOM object or a CSS selector.
this.$mastheadElement = $(mastheadElement);
}
// Add a method to Masthead that creates a normal button
Masthead.prototype.addButton = function (id) {
var $btn = $("<div/>").attr("id", id);
this.$mastheadElement.append($btn);
return $btn;
};
// Add a method to Masthead that creates a 'toggling' button
Masthead.prototype.addTogglingButton = function (id, elementToToggle) {
// ensure we have a jQuerified version of element
elementToToggle = $(elementToToggle);
// Reuse the existing 'addButton' method of Masthead.
var $btn = this.addButton(id);
showMenus($btn, elementToToggle);
return $btn;
};
// return the Masthead constructor function as the module's return value.
return Masthead;
});
And then use this module in our actual application code:
// Application code using Masthead module
require(["Masthead"], function (Masthead) {
// We create a new Masthead around an existing DOM element
var masthead = new Masthead("#masthead");
// We add our buttons.
masthead.addTogglingButton("menu", "#site-navigation-list");
masthead.addTogglingButton("search", "#searchform");
});
The advantage of this approach is that no DOM ids are hard-coded into the module. So we can reuse the Masthead module in other applications that require this functionality, but which may be using different DOM ids.
It might be convenient to think of this as separating the what things are from the how we use them.
This is a simple example, but frameworks/libraries like Backbone and Dojo (and many, many more) take this further.

Resources