I'm trying to update a property of a constructor based on other property values that are getting changed when a certain function fires.
I've tried to create a function as a property and I will still get the same result.
class Rps {
constructor () {
this.userChoice
this.appChoice
this.userPoints = 0
this.pcPoints = 0
this.score = `${this.userPoints} - ${this.pcPoints}`
console.log(score)
this.registeredChoice = []
}
}
After I call a function that increments the user and pc Points, the properties will be updated after i try to console.log() the new object but it will not be the same for the score. The value of the score will not change.
A getter is perfect for this:
class Rps {
constructor () {
this.userChoice
this.appChoice
this.userPoints = 0
this.pcPoints = 0
this.registeredChoice = []
}
get score() {
return `${this.userPoints} - ${this.pcPoints}`
}
}
Alternatively, don't just update properties of the object in that function you have, but call setUser(points) and setPc(points) methods that can update the score property.
I do not know why I am being asked to place commas where periods should be. const cards is saying I can't set it there when this is the way to set a variable.
I have tried to change from const to let and restructure .forEach syntax
class TabLink {
constructor(tabElement) {
// assign this.tabElement to the tabElement DOM reference
this.tabElement = tabElement;
// Get the `data-tab` value from this.tabElement and store it here
this.tabData = this.tabElement.dataset.tab;
// We need to find out if a user clicked 'all' cards or a specific category. Follow the instructions below to accomplish this task:
// Check to see if this.tabData is equal to 'all'
if (this.tabElement.dataset.tab === "all") {
// If `all` is true, select all cards regardless of their data attribute values
this.cards = document.querySelectorAll(".card");
} else {
// else if `all` is false, only select the cards with matching this.tabData values
this.cards = document.querySelectorAll(`.card[tabData="${this.tabData}"]`);
}
// Map over the newly converted NodeList we just created in our if statement above. Convert each this.cards element into a new instance of the TabCard class. Pass in a card object to the TabCard class.
this.cards = Array.from(this.cards).map((card) => new TabCard(card));
// Add a click event that invokes this.selectTab
this.tabElement.addEventListener('click', () => { this.selectTab() });
}
selectTab() {
// Select all elements with the .tab class on them
// const tabs = document.querySelectorAll();
const tabs = document.querySelectorAll('.tab');
// Iterate through the NodeList removing the .active-tab class from each element
Array.from(tabs).forEach((tabs))
link.classList.remove(".active-tab");
}
//
// Select all of the elements with the .card class on them
const cards = document.querySelectorAll('.card');
// Iterate through the NodeList setting the display style each one to 'none'
cards.forEach(card => {
card.style.display = "none";
})
// Add a class of ".active-tab" to this.tabElement
this.tabElement = ".active-tab";
// Notice we are looping through the this.cards array and invoking selectCard() from the TabCard class. Just un-comment the code and study what is happening here.
this.cards.forEach(card => card.selectCard());
console.log(this.cards);
}
'const' can only be used in a .ts file.
';' expected.
',' expected.
',' expected.
Unexpected token. A constructor, method, accessor, or property was expected.
Declaration or statement expected.
I've finally used another logic (using "let" with break), but I would be happy to have (if it's feasible) another solution:
I've built a validation service which iterate over (injected) list of objects that contains regex expressions and relevant message (and input element) for each expression. I'm using every() method to iterate over the regex expressions. The service knows to return true or false when testing the regex.
The problem is that except for getting true\false I would like the consumer of the service to get the relevant message and the input element. So, in the service class I have 2 properties (lets call them "message" and "element") and I thought to set them accordingly. But, when I'm in the context of the every - the "this" refer to the context and not to the class. I thought of sending those 2 properties as parameters to the every method. Is that the best practice?
See relevant code:
export class userValidation
{
constructor() {
this.validationMessage = '';
this.validationElement = '';
//}
validateByExpression(elementValidator, valueToValidate, functionToExec) {
var validationMessage = this.validationMessage;//Trying to get reference - no go
if (elementValidator.regex.test(valueToValidate) == false)
{
//This is the part where I need to store\return the relevant message
validationMessage = elementValidator.message; // fails
return false;
}
else
{
return true;
}
}
validate(validationElement, elementName, valueToValidate)
{
var regexExpList = new Array(validationElement);
var getValidationMessage = this.getValidationMessage;
var validateByExpression = this.validateByExpression;
var validationMessage = this.validationMessage;
return regexExpList.every(function(regexExp) { return
getValidationMessage(validateByExpression, regexExp[elementName],
valueToValidate, validationMessage) });
}
}
I have a tree structure of objects, and their properties have very complicated dependencies on surrounding objects determined by where they are in the tree. I have hard coded a lot of these dependencies, and tried to create some sort of update loop (where if a property gets updated, based on the design, all of the properties that depend on it get updated, and in the correct order), but I want to handle it in a more generic/abstract way, instead of hard coding a bunch of update calls to different objects.
Let's say, for example, I have 1 superclass, and 3 subclasses, and then a separate container object.
Shape
properties: parentContainer, index, left, top, width, height
methods: updateLeft(), updateTop(), updateWidth(), updateHeight()
Square inherits from Shape
Triangle inherits from Shape
Circle inherits from Shape
ShapeContainer
properties: shapes
methods: addShape(shape, index), removeShape(index)
I'll give a pseudocode example update method to illustrate how these dependencies crop up:
Square.updateTop() {
var prevShape = null;
if (this.index != 0) {
prevShape = this.parentContainer.shapes[this.index - 1];
}
var nextSquareInContainer = null;
for (var i = this.index; i < this.parentContainer.shapes.length; i++) {
var shape = this.parentContainer.shapes[i];
if(shape instanceof Square) {
nextSquareInContainer = shape;
break;
}
}
var top = 0;
if (prevShape != null && nextSquareInContainer != null) {
top = prevShape.top + nextSquareInContainer.width;
} else {
top = 22;
}
this.top = top;
}
So, any square objects added to the shapeConatiner will depend on the previous shape's top value and the next square found in the container's width value for its top value.
Here is some code to set up an example shape container:
var shapeContainer = new ShapeContainer();
var triangle = new Triangle();
var circle = new Circle();
var square1 = new Square();
var square2 = new Square();
shapeContainer.addShape(triangle, 0);
shapeContainer.addShape(circle, 1);
shapeContainer.addShape(square1, 2);
shapeContainer.addShape(square2, 3);
So, I guess the crux of the issue is, if I update the above circle's top value, I want the top value of square1 to be automatically updated (because there is a one way dependency between square1's top value, and circle's top value). So one way I can do this (the way I've been doing it, in combination with some other specific knowledge of my problem domain to simplify the calls), is to add the code similar to the following to Circle's updateTop method (really it would have to be added to each shape's updateTop method):
Circle.updateTop() {
// Code to actually calculate and update Circle's top value, note this
// may depend on its own set of dependencies
var nextShape = this.parentContainer.shapes[this.index + 1];
if (nextShape instanceof Square) {
nextShape.updateTop();
}
}
This type of design is fine for a few simple dependencies between objects, but my project has dozens of types of objects with probably hundreds of dependencies between their properties. I've coded it this way, but it is very difficult to reason about when trying to add new features, or troubleshoot a bug.
Is there some sort of design pattern out there to set up dependencies between object properties, and then when one property is updated, it updates all of the properties on other objects that depend on it (which may then trigger further updating of properties that depend on the now newly updated properties)? Some sort of declarative syntax for specifying these dependencies would probably be best for readability/maintainability.
Another issue is, a property may have several dependencies, that ALL must be updated before I want that property to update itself.
I've been looking into a pub/sub type of solution, but I thought this was a complicated enough problem to reach out for help. As a side note, I'm working in javascript.
Here is the hackish solution I came up with. I create a wrapper class, that you pass in anonymous functions for getter/setter/updaters. Then you make a call of prop1.dependsOn(prop2) to declaratively set up dependencies. It involves setting up a directed acyclic graph of the dependencies between object properties, and then when a property value is updated, explicitly making a call to resolve the related dependencies using a topological sort. I didn't put much thought into efficiency, and I bet somebody could come up with a much more robust/performant solution, but I think this will do for now. Sorry for the code dump, but I thought it could be of some help to somebody trying to solve a similar problem down the road. If somebody wants to make this syntactically cleaner, be my guest.
// This is a class that will act as a wrapper for all properties
// that we want to tie to our dependency graph.
function Property(initialValue, ctx) {
// Each property will get a unique id.
this.id = (++Property.id).toString();
this.value = initialValue;
this.isUpdated = false;
this.context = ctx;
Property.dependsOn[this.id] = [];
Property.isDependedOnBy[this.id] = [];
Property.idMapping[this.id] = this;
}
// Static properties on Property function.
Property.id = 0;
Property.dependsOn = {};
Property.isDependedOnBy = {};
Property.idMapping = {};
// Calling this updates all dependencies from the node outward.
Property.resolveDependencies = function (node) {
node = node.id;
var visible = [];
// Using Depth First Search to mark visibility (only want to update dependencies that are visible).
var depthFirst = function (node) {
visible.push(node);
for (var i = 0; i < Property.isDependedOnBy[node].length; i++) {
depthFirst(Property.isDependedOnBy[node][i]);
}
};
depthFirst(node);
// Topological sort to make sure updates are done in the correct order.
var generateOrder = function (inbound) {
var noIncomingEdges = [];
for (var key in inbound) {
if (inbound.hasOwnProperty(key)) {
if (inbound[key].length === 0) {
// Only call update if visible.
if (_.indexOf(visible, key) !== -1) {
Property.idMapping[key].computeValue();
}
noIncomingEdges.push(key);
delete inbound[key];
}
}
}
for (var key in inbound) {
if (inbound.hasOwnProperty(key)) {
for (var i = 0; i < noIncomingEdges.length; i++) {
inbound[key] = _.without(inbound[key], noIncomingEdges[i]);
}
}
}
// Check if the object has anymore nodes.
for (var prop in inbound) {
if (Object.prototype.hasOwnProperty.call(inbound, prop)) {
generateOrder(inbound);
}
}
};
generateOrder(_.clone(Property.dependsOn));
};
Property.prototype.get = function () {
return this.value;
}
Property.prototype.set = function (value) {
this.value = value;
}
Property.prototype.computeValue = function () {
// Call code that updates this.value.
};
Property.prototype.dependsOn = function (prop) {
Property.dependsOn[this.id].push(prop.id);
Property.isDependedOnBy[prop.id].push(this.id);
}
function PropertyFactory(methodObject) {
var self = this;
var PropType = function (initialValue) {
Property.call(this, initialValue, self);
}
PropType.prototype = Object.create(Property.prototype);
PropType.prototype.constructor = PropType;
if (methodObject.get !== null) {
PropType.prototype.get = methodObject.get;
}
if (methodObject.set !== null) {
PropType.prototype.set = methodObject.set;
}
if (methodObject.computeValue !== null) {
PropType.prototype.computeValue = methodObject.computeValue;
}
return new PropType(methodObject.initialValue);
}
And here is an example of what setting up a property looks like:
function MyClassContainer() {
this.children = [];
this.prop = PropertyFactory.call(this, {
initialValue: 0,
get: null,
set: null,
computeValue: function () {
var self = this.context;
var updatedVal = self.children[0].prop.get() + self.children[1].prop.get();
this.set(updatedVal);
}
});
}
MyClassContainer.prototype.addChildren = function (child) {
if (this.children.length === 0 || this.children.length === 1) {
// Here is the key line. This line is setting up the dependency between
// object properties.
this.prop.dependsOn(child.prop);
}
this.children.push(child);
}
function MyClass() {
this.prop = PropertyFactory.call(this, {
initialValue: 5,
get: null,
set: null,
computeValue: null
});
}
var c = new MyClassContainer();
var c1 = new MyClass();
var c2 = new MyClass();
c.addChildren(c1);
c.addChildren(c2);
And here is an example of actually updating a property once all of this infrastructure is set up:
c1.prop.set(3);
Property.resolveDependencies(c1.prop);
I feel like this is a pretty powerful pattern for programs that require really complicated dependencies. Knockout JS has something similar, with computedObservables (and they use a wrapper in a similar fashion), but you can only tie the computed property to other properties on the same object from what I can tell. The above pattern allows you to arbitrarily associate object properties as dependencies.
How do you achieve the following thing in Javascript
1) var MyObject={
2) tableView:true,
3) chartView:!(this.tableView)
4) }
The code at line number 3 is not working. Whats wrong in that line ?
What i basically want to do is set "chartView" to opposite of "tableView" whenever tableView is set from code.
Since you're in the process of creating the object, this is not bound to that object. Moreover, since you want chartView to always evaluate to the opposite of tableView, even if the latter changes further down the line, a function would be a better approach:
var MyObject = {
tableView: true,
chartView: function() {
return !this.tableView;
}
};
Now you can do:
var chartView = MyObject.chartView(); // false.
MyObject.tableView = false;
chartView = MyObject.chartView(); // true.
You can't use this to refer to an object in an object literal's properties. You can use this inside a function that is a method of that object:
var MyObject = {
tableView: true,
chartView: function () {
return !this.tableView;
}
}
Based on your requirement, this may be an answer too,
var MyObject = {
view : function(bool){
this.tableView = bool;
this.chartView = !(bool);
}
tableView: true,
chartView: false
}
MyObject.view(false)
console.log(MyObject.tableView); // Outputs false
console.log(MyObject.chartView) // Outputs true
This way you will always have opposite of tableView in chartView with a single function call.