I'm using inheritance to implmenet a reuseable forms app.
Expression parameter can be dependent on one or more other numeric/constant ot other expression parameters (the relation is many to many so heirarchy wont work here). Once all my dependent parameters evaluated them self (calcualted if expression or validated if user input) I can now calculate my self.
I'm looking for a way to subscribe to my siblings but the problem is that during creation the sibling does not neccasarily exists yet.
I set up a small example on this Fiddle.
To see this not working in action lets change the values from the console
d.parameters()[0].value(10) // expecting parameter C to sum up to 20.
d.parameters()[2].value() // Nothing (this should also update ont he screen).
d.parameters()[1].value(20) // expecting parameter C to sum up to 30.
d.parameters()[2].value() // Still nothing.
So Ive tried sevral things but i think i'm barking up the wrong tree here.
Fetching the parent using ko.dataFor(document.body) or
fetching the object from the DOM using the same function.
I've played around with deferEvaluation as you can see in the code
to force KO to first create the parameters and then apply the
binding. seems to do nothing.
Tried creating a observableArray with the links to the params and a
computed based on the array but the problom remain.
Appreciate any help here.
Bonus question, without losing focus from the main one, somehing I cant explain going on on line 73.
Related
I've got a simple example demonstrating what I'm seeing: https://stackblitz.com/edit/lit-element-example-3pdnwk?file=index.js.
Basically when the first child element renders, the text property is set correctly. However on the second render, the text property is undefined first and then updated to be the correct value.
This breaks being able to depend on _firstRendered() to have the correct values assigned to the properties.
Am I doing something really off here?
Update: Here is a better example using a similar method provided in the lit-html documentation: https://stackblitz.com/edit/lit-element-issue?file=index.js
Am I doing something really off here?
maybe? :) Hopefully you can help me to understand why you chose your implementation and I can look into it further.
The part I'm stuck on is why you create and replace the child element inside the parent element like this:
this._child = html`<child-element text="${text1}"></child-element>`;
From what I understand so far, that code uses a lit-html helper function to create a lit-html TemplateResult. You then replace it with another one in the timeout callback:
this._child = html`<child-element text="${text2}"></child-element>`;
So instead of just re-drawing only the stuff that changed (a string), your code creates a new TemplateResult and redraws that. This also calls the child element constructor again and causes the text node to go undefined for a moment as you noted. Here is console output added to your impl to show when the constructor and render functions get called for parent and child:
https://stackblitz.com/edit/lit-element-example-ftlbz7?file=index.js
From inspecting the DOM tree, your example produces this DOM structure:
<parent-element>
#shadow-root
<div>
<child-element>
#shadow-root
<div>
Suppose I need to produce that same DOM structure and have the same text node update in response to the timeout callback, I would probably handle it in the parent render function:
_render({ parenttext }) {
return html`<div><child-element text="${parenttext}"></child-element></div>`;
}
which ensures that the child constructor is only called once, and only the data that actually changes gets redrawn.
If I understand correctly, that's how lit-element is designed to be used (expressing an app or element's render as a function of its data). That way we can rely on the browser to just redraw any changes to the data. This should theoretically be faster (altho I haven't tested it).
Code sample here:
https://stackblitz.com/edit/lit-element-example-exrlxw?file=parent-element.js
Lmk what I'm missing from your tests and I can look into it more.
Edited to add:
I noticed that overriding _shouldRender to prevent the element from rendering with undefined props prevented the element from rendering with undefined props, but it didn't fix _firstRendered, which was still firing when props were undefined.
_firstRendered, unlike _didRender, is not specifically called as a result of _render; it is called from the ready() callback, which is inherited from Polymer's properties-changed mixin. In Polymer, ready() fires when the element is added to the DOM. I thought properties should be initialized by then, so this is still pretty weird.
Anyways, this means it is possible to create an element that never renders (i.e _shouldRender always returns false), but _firstRendered still fires. Lol. Sample: https://stackblitz.com/edit/lit-element-first-rendered?file=index.js.
I'm not honestly sure what to make of any of this. I'll raise an issue on the lit-element github when I've read a few more things from the documentation (or you can, if you get there first).
This is no longer an issue as of 0.6.0-dev.5
http://codepen.io/adamchenwei/pen/yagLLZ?editors=0010
I have FormatModule component which is two levels deep from RepeatModule. I want whenever onClick is triggers onClick={this.props.changeFormat.bind(this)} on the FormatModule, it will change all the statues for all the of islamic to islamic: '09999999',, or whichever got passed in from changeFormat function inside the RepeatModule
I heard this is the only way to manipulate state massively when its nested inside a list of components.
For now, when I click on where onClick={this.props.changeFormat is implemented, values are not response to the change. I wonder where is the place I missed link? Since changeFormat is a function that got passed in from the top parent component down to the FormatModule... unless its not the way to do it?
NOTE: I need a solution that not involving Redux or Flux
With a help of colleague, its already fixed in my code pen: http://codepen.io/adamchenwei/pen/yagLLZ?editors=0010
So the issue was that:
I bind(this) in the wrong scope. Should only bind inside the RepeatModule
the newFormat state should follow the format of the original format ( in this case it was an array so newFormat should be an
array as well!
Enjoy!
(Hope whoever voted down my questions come back and learn their stuff before put others down first, especially without any reason)
I maintain a custom library consisting of many dijit widgets at the company I work at.
Many of the defects/bugs I have had to deal with were the result of this.inherited(arguments) calls missing from overriden methods such as destroy startup and postCreate.
Some of these go unnoticed easily and are not always discovered until much later.
I suspect I can use dojo\aspect.after to hook onto the 'base' implementation, but I am not sure how to acquire a handle to the _widgetBase method itself.
Merely using .after on the method of my own widget would be pointless, since that wouldn't check whether this.inherited(..) was inded called.
How can I write a generic test function that can be passed any dijit/_WidgetBase instance and checks whether the _widgetBase's methods mentioned above are called from the widget when the same method is called on the subclassing widget itself?
Bottom-line is how do I acquire a reference to the base-implementation of the functions mentioned above?
After reading through dojo's documentation, declare.js code, debugging, googling, debugging and hacking I end up with this piece of code to acquire a handle to a base method of the last inherited class/mix-in, but I am not entirely happy with the hackiness involved in calling getInherited:
Edit 2 I substituted the second param of getInherited with an empty array. While I actually get a reference to the method of the baseclass using aspect doesn't work. It appears this approach is a bust.
require(['dijit/registry','dojo/_base/declare','mycompany/widgets/widgetToTest'],
function(registry,declare,widgetToTest)
{
var widget = registry.byId('widgetToTestId');
var baseStartup = getBaseMethod(widget,'startup');
function getBaseMethod(widget,methodName){
return widget.getInherited(methodName,[]);
}
//This is the method body I want to use .after on to see if it was called, it returns the last overriden class in the array of inherited classes. (a mixin in this case, good enough for me!)
alert(baseStartup);
});
I have given up trying to use dojo/aspect.
I have instead opted to modify the code of our custom base widget to incorporate snippets such as the one below. They are automatically removed when creating a release-build in which console-calls and their content are removed:
console.log(
function(){
(this._debugInfo = this._debugInfo|| {}).postCreate=true;
}.call(this)
);
A simple method in boilerplate code I added near the unittests is available so that I can call it on all mycompany.widgets.basewidget instances in their respective unittests.
I am trying to create recursive grid layout using directives.
There is a parent container(appliedgrids) which contains array of grids inside it.
A grid contains array of columns inside it.
Each column has two properties: span(width of column) and data (data inside column)
Each column data contains either grid again or a widget. If it contains grid then it make recursive call to grid directive.
My problem is when I delete a grid using remove button inside it- it gets removed from appliedgrid container but two way data binding doesn't work as it should. In place of current grid, last grid gets removed from the UI.
Link- http://plnkr.co/edit/DzKIHKvJdLoZiYY3jgDx?p=preview
Steps to reproduce:
1) Click remove button on first grid, you will see that in place of first, second grid gets removed. While json data of appliedgrid contains second grid inside it. So two way binding of angular doesn't work as it supposed to.
I did a little thinking in my previous answer and it turns out it was not correct.
Firstly, do not use track by $index. It makes no sense in your case. track by is an optimisation of ng-repeat to correlate (potentially new) objects in the array that are "business-wise" equal with old objects in the array, so that it re-uses scopes and DOM elements in an effort to minimize DOM manipulation. That is: if you give ng-repeat a hint which new object in the new array is "equal" to an old object in the old array, it will reuse its scope and hopping that the new object is not dramatically different compared to the old one, less $watch callbacks will fire and less DOM updates will occur.
Your actual problem is that you are "statically" or "once-off" binding data with statements like:
$scope.gridIndex = $parse($attrs.gridIndex)($scope);
$scope.gridValues=$parse($attrs.appliedgrid)($scope);
$scope.gridParent=$parse($attrs.appliedgrids)($scope);
The first grid item is indeed removed from the array but ng-repeat does not remove its scope and DOM element because track by $index is used. But still, the new 0-index object (2nd, previously) is used to update the scope (the one created for the 1st object).
You do not see this reflecting to the UI because $scope.gridValues was evaluated in the beginning and is not evaluated again.
So, even though $scope.appliedgrid now points to [{span:12,data:[object]}], $scope.gridValues still points to [{span:6,data:[object]},{span:6,data:[grid2]}].
Removing track by $index solves the problem because ng-repeat tracks objects by reference so each object is associated with the same scope until it is removed from the array.
You can verify it with AngScope, a small Firebug-based scope inspector. You have to open it in a separate tab with "Launch the preview in a separate window" in order for it to work in plunker.
I tried to find a quick fix for it but there was no luck. I guess, you have to re-write it using isolated scopes and real 2-way binding.
Short answer: remove track by $index from ng-repeat.
Long answer: When you are write track by $index you're actually saying to ng-repeat that:
The 1st DOM element will be associated to an object that is tagged as the "0" object
The 2nd DOM element will be associated to an object that is tagged as the "1" object
When you remove the 1st object from the array, angular digests and finds out the following:
The 1st DOM element is still associated to an object tagged as the "0" object
The 2nd DOM element is not associated to any object, so it has to be removed
This is because when ng-repeat runs again, your previously 2nd object which was tagged as "1", is now your 1st and only object which is tagged as "0", since the $index is evaluated again starting from 0.
Angular believes that the 1st DOM element still points to the same object cause it finds it tagged as "0", regardless that it's a completly different object. Under the hood, $scope has the correct model values but ng-repeat skips re-rendering of the DOM element.
It very difficult to write down what really happens. Hope I got it right and helped you.
Does anybody have a minute to take a look at a puzzling problem I'm having with Knockout JS and binding select lists?
The person's favourite color should be selected in the list by calling value: favColorId in the select list, rather than with the function-based call of value: favColorId(), something very strange is going on here, I've never used () in the past, it's also causing some other weird issues where it won't recall the value into the span (so changing the selected item does nothing).. I have tried recreating a simple sample as best I can demonstrating the issue.
http://jsfiddle.net/goneale/ph8Jw/
I have included my mapDictToArray() function but it simply converts a
javascript object into a key-value JS array. I wouldn't think that is
contributing to the problem.
Actually, that was part of the problem. The function returns a JavaScript array, not an observable array and therefor can't be used properly by Knockout. I've made the following changes to your code:
// The "mapDictToArray" makes a normal JS array, not a ko.observableArray();
// You can't simply "merge" a JS array with an observableArray(); you'll need
// some extra functionality for that: ko.utils.arrayPushAll()
// viewModel.colors(mapDictToArray(dict));
ko.utils.arrayPushAll(viewModel.colors(), mapDictToArray(dict));
// Apply the bindings *after* you've added the contents to the "colors" observable, in order to
// get the correct selected value
ko.applyBindings(viewModel);
That should do the trick (with the correct HTML without the () )!
JSFiddle.
UPDATE
I thought about my solution, but something wasn't correct. The only thing that was correct, was the part that you need to apply the bindings after you've added the contents of the colors observable. This is your fiddle, with that part moved down.
This works in your case, but you'll need to use the arrayPushAll method when there is already data inside the observableArray. This method merges, while you overwrite it when not using it (example with data inside the observable).