Vue.js 3 JavaScript Objects members losing ref reactivity - vue.js

I'm updating a web app from using Knockout.js Templates to Vue 3 Components. This issue is not in the components but in the JS where I'm creating objects to be used in the components.
I'm running into strange behaviour around using refs where an object member is not always being set as a ref. I haven't been able to recreate this in an example but a simplified version of the structure is that we have an attribute that returns an object that contains the ref value.
function Attribute(val) {
var value = ref(val);
return {
value: value
}
}
We have a builder that is used to add labels and other items such permissions and classes to the UI.
function UIBuilder() {
var self = this;
var newElement = {};
function newText(value) {
newElement.inputType = 'TEXT';
newElement.value = value;
return self;
}
function addLabel(lbl) {
newElement.label = lbl;
return self;
}
function build() {
return newElement;
}
this.newText = newText;
this.addLabel = addLabel;
this.build = build;
}
Finally there is a function that returns an object that contains everything that the component needs.
function TextInput(initValue) {
var self = this;
self.label = initValue.label;
self.value = initValue.value;
var textInput = {
label: self.label,
value: self.value
};
return textInput;
}
Then I create an object to be passed to the component.
var attr = new Attribute(5225);
var textBox = new TextInput(new UIBuilder().newText(attr).addLabel('Description').build());
This structure works using Knockout and I'm trying to keep as much of the existing code as possible.
Most of the time this works but there are some occasions where the value is coming in as a string rather then a ref. I haven't been able to isolate why this is happening. While debugging most of the time the values for initValue.value and self.value look like this in the watch on VS Code.
On some occasions it changes to string values even though the objects were created using the same functions.
I checked the initValue object when taking the screenshot and it appeared to be a ref
As far as I can see the value should stay as a ref. I'm not unwrapping it in code. Why is this happening? What should I look for?

Related

How to add additional properties to be passed through sequelize object in express

So for example I have a sequelize model as follows:
// MyModel.js
module.exports = (sequelize, DataTypes) => {
const MyModel = sequelize.define('MyModel',{
foo: DataTypes.STRING,
});
return MyModel
}
And then I use this model to express templating engine using controller as follows:
app.get('/foobar',async function(req,res,next){
var myModel = await MyModel.findById('abcd1234');
myModel.bar = bar
return res.render('foobar',{
myModel: myModel
});
})
and my foobar.pug is like this:
html
#{JSON.stringify(myModel)}
Apparently I can find the field called foo, but I can't get the field called bar, how do I pass this additional calculated field from my controller through my model?
Reason behind this is :
var myModel = await MyModel.findById('abcd1234');
// will return an instance of MyModel not json
// So you can't just do
myModel.bar = bar;
To make it happen ( Convert instance to JSON Object )
var myModel = await MyModel.findById('abcd1234').toJSON();
// Now this will return the JSON object and not instance of MyModel
// Now this will work
myModel.bar = bar;
toJSON() is sequelizejs's model's method , you can convert it via javascript function also.
If you want to retain the sequelize object , retain it in different variable
var myModelInstance = await MyModel.findById('abcd1234');
var myModel = myModelInstance.get({plain: true});
// OR
var myModel = myModelInstance.toJSON();
// Now this will work
myModel.bar = bar;
These are the possible ways of doing , but because of lack of
requirement and code this is the best I can suggest , you can still
look into GETTER , if you need the extra fields inside
instance.
For anyone looking for this in 2K22 and after :D,
you can use DataType.VIRTUAL when registering a field,
this allow predefining additional fields that will be used and keep it at serialize time but not persist into database.

View not updating after changing value of component array

I need to update my view on changing array in my *.component.ts
I use
public getFolders() : void {
this.webService.getFolders({client_id : this.local.get('clientUser').client_id}).subscribe( this.processSkills.bind(this, this.local.get('clientUser')))
}
processSkills(res: any, myobj): void {
if(res.status){
myobj.folders = res.folders;
this.local.set('clientUser', myobj);
this.userObj = this.local.get('clientUser');
}
}
It updates my array i saw in console it update my session value which i saw after pressing F5 but it doesn't update my view
Initially i am assigning my array to variable from my session object.
import { BehaviorSubject } from 'rxjs';
private messageSource = new BehaviorSubject(this.local.get('clientUser'));
currentMessage = this.messageSource.asObservable();
I resolved it and found a solution to pass our array into session and make the code into our provider which works as observable to my array and then recieve
currentMessage to our receiver function to update on view.
this.webService.currentMessage.subscribe(message => {
this.userObj = message;
})
will receive updated value and will reflect on view.

Aurelia DataTables Recompile

I've been exploring Aurelia and so far have loved what I've seen. I've come accross an issue that I'm not really sure how to solve. I used jquery datatables for large results in my current app with angular, using server side fetches. Datatables has a function you can call whenever a new row is added to the table (fnRowCallback - http://legacy.datatables.net/ref#fnRowCallback, or "createdRow" - https://datatables.net/examples/advanced_init/row_callback.html#) - This is really handy as you can recompile the dom after each row (costly I know).
This enables you to reference functions that exist in the current scope (or viewModel) that the datatable exists in. For example:
In my view model:
export class DataTableTest{
test(){
alert('this is a test');
}
}
In the return results from a datatable fetch:
{name:'blah',age:40,actions:"<a click.delegate='test();'>Test</a>"}
For some reason I can't seem to figure out how to recompile an element once it has been added to the dom.
Does anyone have any ideas how you could do this?
UPDATE:
These are the original options I pass to datatables:
var options = {
"fnRowCallback": function (nRow) {
$compile($(nRow).contents())(scope);
}
};
I've tried the following after injecting that compiler service:
"fnRowCallback": function (nRow) {
this.compiler.compile($(nRow).contents()).fragment.innerHTML;
},
But I always get Uncaught TypeError: Cannot read property 'compile' of undefined - I do this in the "attached" function.. If I console.log(this.compiler) outside of these options, it's available. Also, we don't need to return html back to datatables, just run the compile on the contents. Many thanks for all your help!
You can use a compiler service to compile the element:
import {inject, ViewCompiler, ViewResources, Container} from 'aurelia-framework';
/**
* Compiler service
*
* compiles an HTML element with aurelia
*/
#inject(ViewCompiler, ViewResources, Container)
export class Compiler {
viewCompiler: any;
resources: any;
container: any;
constructor(viewCompiler, resources, container) {
this.viewCompiler = viewCompiler;
this.resources = resources;
this.container = container;
}
compile(templateOrFragment, ctx = null, viewSlot = null):any {
if (typeof templateOrFragment === "string") {
var temp = document.createElement('span');
temp.innerHTML = templateOrFragment;
templateOrFragment = temp;
}
var view = this.viewCompiler.compile(templateOrFragment, this.resources).create(this.container, ctx);
return view;
}
}
I use this in Kendo in the cell template callback function (it lets you return a string that will become the cell contents)
function(dataItem) {
var cellctx = { "$item": dataItem, "$parent": ctx };
return this.compiler.compile(templateString, cellctx).fragment.innerHTML;
}
(this happens in Aurelia's bind callback so the ctx is the executionContext)
I just wrap the current data item up in a context and alias it as $item so I can work with it.
Looks something like this:
<kendo-grid>
<kendo-grid-col title="Main Office" field="IsMainOffice">
<kendo-template><img if.bind="$item.IsMainOffice" src="/content/img/accept.png" /></kendo-template>
</kendo-grid-col>
</kendo-grid>

Creating new upshot js entities

I'm building a site as a Single Page Application using ASP.NET MVC 4 Beta .
The sample app talks about adding new entities and it uses a constructor function for it's product entity.
However I have many entity types and I'm not going to write a constructor function for each one. This is how I am creating a new entity (name is the name of the datasource and dataTarget.upshot.upshotData is the list of entities I get back from the GetEntities method
in coffeeScript...
newItem = {}
for field, def of upshot.metadata(upshot.dataSources[name]._entityType).fields
do (field, def) ->
if def.array
newItem[field] = new ko.observableArray()
else
newItem[field] = new ko.observable()
upshot.addEntityProperties newItem, upshot.dataSources[name]._entityType
dataTarget.upshot.upshotData.push newItem
my question is if this is the best way to do it or am I missing something? I'm surprised that upshot does not seem to have a createEntity method.
in javascript...
newItem = {};
_ref = upshot.metadata(upshot.dataSources[name]._entityType).fields;
_fn = function(field, def) {
if (def.array) {
return newItem[field] = new ko.observableArray();
} else {
return newItem[field] = new ko.observable();
}
};
for (field in _ref) {
def = _ref[field];
_fn(field, def);
}
upshot.addEntityProperties(newItem, upshot.dataSources[name]._entityType);
dataTarget.upshot.upshotData.push(newItem);
var newThing = {};
var typeName = "MyType:#MyNamespace";
upshot.map({ SomeProperty: "my value" }, typeName, newThing);
upshot.addEntityProperties(newThing, typeName);
This will create your object with the entity properties mapped to observables, and will allow you to set properties (see SomeProperty:"my value").

Trouble defining method for Javascript class definition

I'm somewhat new to object oriented programming in Javascript and I'm trying to build a handler object and library for a list of items I get back from an API call. Ideally, I'd like the library functions to be members of the handler class. I'm having trouble getting my class method to work however. I defined as part of the class bcObject the method getModifiedDateTime, but when I try to echo the result of the objects call to this method, I get this error:
Error on line 44 position 26: Expected ';'
this.getModifiedDateTime: function(epochtime) {
which leads me to believe that I simply have a syntax issue with my method definition but I can't figure out where.
response(
{
"items":
[
{"id":711,"name":"Shuttle","lastModifiedDate":"1268426336727"},
{"id":754,"name":"Formula1","lastModifiedDate":"1270121717721"}
],
"extraListItemsAttr1":"blah",
"extraListItemsAttr2":"blah2"
});
function response(MyObject) {
bcObject = new bcObject(MyObject);
thing = bcObject.getModifiedDateTime(bcObject.videoItem[0].lastModifiedDate);
SOSE.Echo(thing);
}
function bcObject(listObject) {
// define class members
this.responseList = {};
this.videoCount = 0;
this.videoItem = [];
this.responseListError = "";
// instantiate members
this.responseList = listObject;
this.videoCount = listObject.items.length;
// populate videoItem array
for (i=0;i<this.videoCount;i++) {
this.videoItem[i] = listObject.items[i];
}
this.getModifiedDateTime: function(epochtime) {
var dateStringOutput = "";
var myDate = new Date(epochtime);
dateStringOutput = myDate.toLocaleString();
return dateStringOutput;
};
}
You use = to assign values in JS, not ::
this.getModifiedDateTime = function(epochtime) {
You should use the = operator for methods defined as you did there (this.<methodName> = function (...) {).
The colon notation is used when declaring object literals.