angular 2 data polluted between duplicate components? - javascript

I can't figure out what I'm doing wrong here, but when I declare two components like this:
<todo-component [options]="selectOptions" [choice]="slideToggleSelection" (choiceChange)="handle($event)" group="weird">
</todo-component>
<todo-component [options]="selectOptions2" [choice]="slideToggleSelection2" (choiceChange)="handle($event)" group="test">
</todo-component>
... changing the value of one affects the value of the other. Check out this plunker for an example. -- for instance, selecting 'Y' in one actually selects them in both. I think I'm misunderstanding some fundamental concept but I'm banging my head against the wall on this one.

I think this is related to the [attr.name]="group". If you change it to [name]="group" it seems to work.

Related

Different results for %%GLOBAL_ProductID%% and 'actual' product ID - Bigcommerce - why?

I am working on a project where I need to reference an unchanging attribute of a product (an item on the site). In the past I have referenced them using the value of an attribute called "data-product". This value is the ID of the product that has been assigned to it by Bigcommerce, so it will never change. Yesterday I discovered the global product_id variable (%%GLOBAL_ProductID%%) so I did a few tests.
When I take the value of the product ID variable and print it to the console:
<span id="the-id-of-the-product">%%GLOBAL_ProductId%%</span>
<script>
var theProductIdNumber = $.trim($('span#the-id-of-the-product').text());
console.log(theProductIdNumber);
</script>
I get a different number then when I inspect the same product and look at the value of the 'data-product' attribute:
Even more confusing, I found one case where the value for %%GLOBAL_ProductID%% what the same number (string) for two different products.
Can you tell me why this is happening? I assumed that using the BC defined global variable would be a more solid method of referencing the product, since thats kind of what it seems like it's for.
As always, your time and help is much appreciated, and I hope you all have a nice day.
I realize this is an old post but I had the same problem today and believe I understand what is going on.
My JavaScript was referencing GLOBAL_ProductId at the bottom of the product.html template. The value was never correct and was also unchanging. Looking deeper, I noticed that it always seemed to be the ID for the last product shown in the Related Products region.
I took the JavaScript variable initialization out of product.html and moved it to ProductDetails.html and the problem was solved. It looks like when the Related Products region is generated, someone decided to recycle the Global_ProductID variable. Or...something like that, yuk.
Your theme may not even include a ProductDetails.html, but if you tinker around with where you initialize variables that reference GLOBAL_ProductID, that might square you away.

Angular radio ng-change works only first time

I can't understand why angular ng-change function are called only in first click. In this example
http://jsfiddle.net/ZPcSe/5/
function is called every time when i change current radio selection, but in my code something is wrong
http://jsfiddle.net/4jL3u8ko/1/
Can someone change my code to work like first example, and explain why it isn't working?
Great question.
This is not an answer but one may call this explanations to answers and any further problems that may occur. And this happens quite often, so its important to understand. The answer given by #Victor is ok and the comment of #Atias is also helpful.
Explanation -
Simple explanation : ng-repeat forms child scope.
Little detailed :
So your application has 3 scopes (or may increase depending on the number of values in $scope.radioButtons). Let me name them - parentScope(main scope), childScope1(scope of first element of ng-repeat) and childScope2(scope of second element of ng-repeat).
Parent scope variables : calledFunctions(array), radioButtons(object) and newValue(function)
ChildScope1 variables : name(assigned a literal at the start), val(assigned an object at start) and value(it has no value, or undefined)
ChildScope2 variables : name(assigned a literal at the start), val(assigned an object at start) and value(it has no value, or undefined)
What happens when you click on the radio button of childScope1(for first time):
ChildScope1.value = ChildScope1.name or ChildScope1.value= "Radio1"; the ng-change directive checks if this scope's model has been changed? Yes, as it was undefined and now it has a literal("Radio1")!! So call ChildScope1.newValue(), which obviously is not present. Therefore now look for parent- call parentScope.newValue(). This is present, so execute it.
keep in mind that ChildScope1.value= "Radio1";
After clicking on other radio buttons......
Now lets click 2nd time on ChildScope1's radio button. After clicking it- ChildScope1.value = ChildScope1.name or ChildScope1.value= "Radio1"; the ng-change directive checks if this scope's model has been changed??? No!! Because it still contains the same literal vaule as before, so do not even look for ChildScope1.newValue() or ParentScope.newValue() function.
Now same thing happens with ChildScope2.
Hope this explains why your fiddle works like a one time binding, or how #Victor or #Atias are correct.
Simply the solution is - The ng-model of ChildScope1 or ChildScope2 or any other child scopes, should point to a variable of parent scope. So you can use $parent or make an object in parent scope(main scope) with a property( eg.- ParentVal={ChildVal = ""};). And in ng-model inside ng-repeat- write ng-model=ParentVal.ChildVal.
Sorry for my poor english and please pardon my spelling mistakes if there is any.
Thanks
ng-model is tricky. You should always, always have a dot in your models, or you get this kind of problem where you are creating several models and you think you only have one.
As a quick fix, use $parent.value instead of just value in your ng-model and ng-change.
As a good fix, have a proper model object in the scope, instead of storing values directly in the scope:
$scope.model = {};
ng-model="model.radiosValue"
As an even better fix, use the controllerAs pattern and use that object as the view model.

Angular ngGrid Tree Control: Make a round trip on group expand

I am trying to use ngGrid to make somewhat of a "tree-control" which I can build dynamically by calling API's. ngGrid allows for grouping on rows, yet the nature of it requires that all rows be present at the beginning. This is unfortunate for the fact that an API to pull back all generation data for a File Integrity Monitoring system would be insanely slow and stupid. Instead, I wish to build the "tree" dynamically on the expansion of each generation.
I am trying to inject children (ngRows) into a group-row (ngAggregate) on a callback, yet I do not think that I am calling the correct constructor for the ngRows for the fact that the rows are ignored by the control
Through the use of the aggregateTemplate option on the gridOptions for ngGrid, I have been able to intersept the expansion of a group quite easily.
(maybe not easily, but still)
I've replaced the ng-click of the default template:
ng-click="row.toggleExpand()"
with:
ng-click="$parent.$parent.rowExpanded(row)"
I know that it's a bit of a hack, but we can get to that later. For now, it gets the job done.
The way that I discovered how to work my way up the $scope to my rowExpanded function was by setting a breakpoint in ngGrid's "row.toggleExpand" function and calling it from the template as so:
ng-click="row.toggleExpand(this)"
Once I retrieve the group I want, I call an API to get the children for said group. I then need to make the return as children of the row. I decided to do this by calling ngGrid's ngRow factory:
row.children = [];
for(var i = 0; i < childData.length; i++)
{
row.children[row.children.length] = row.rowFactory.buildEntityRow(childData[i], i);
}
row.toggleExpand();
... yet this does not appear to be working. The rows are not showing up after I do the expand! Why won't my rows show up?
Here's my current Plunker!
By the way
I've placed a debugger statement within the group-expand callback. As long as you have your debugger open, you should catch a breakpoint on the expansion of a group.
Thanks everybody!
I found my answer, I'm an idiot....
I got this control working, and then realized that it was a total hack, that I could have used the control the way it was meant to be used and it would have worked much better, had much better work-flow, and it would have saved me an entire day of development. If you are wondering how you use the control this way, the answer is that you don't.
I got the stupid thing to work by updating my data structure after the round trip and forcing the grid to refresh, pretty obvious. I had to set the grid options so that groups were always expanded and I had to control the collapser icon logic myself, outside of ngGrid. I never called row.toggleExpand. I also hid any rows with null values by a function call within an ng-if on my rowTemplate. After all that was said and done, I put my foot in my mouth.

AngularJS 1.2.13 ng-if does not re-evaluate $resource result

I have something like the following in a template:
<div ng-if="foo">
...
</div>
<div ng-class="foo && 'foo-is-present'">
...
</div>
In the controller for this scope, I have the following:
$scope.foo = $resource("path/to/resource").query();
The resource loads just find and returns a simple JSON array (verified by watching request in Chrome), and other debugging shows that foo contains the array, exactly as it should. The second div applies the foo-is-present class as expected, however the first div still has its ng-if evaluating to false, preventing that div from rendering.
This doesn't seem right, as I want that first div to show up once the results of the resource have been loaded. What am I missing here?
EDIT It turns out ng-if's version of "truthy" does not include arrays, even if the array is not empty. I was able to work around this by adding turning the condition into ng-if="!!foo", but this feels hacky. If anyone has any better insight or solutions, please share!
Also in the Edit, above, but added as an answer so it is more immediately visible as a (hopefully) useful workaround.
It turns out ng-if's version of "truthy" does not include arrays, even if the array is not empty. I was able to work around this by adding turning the condition into ng-if="!!foo", but this feels hacky. If anyone has any better insight or solutions, please share!
What version of AngularJS are you using?
I'm using 1.2.10 and:
$scope.foo = [];
ng-if="foo"
Evaluates to true.
Perhaps the first div is not within the scope of the controller that contains foo?

EmberJS - Adding a binding after creation of object

I am trying to bind a property of an object to a property that's bound in an ArrayController. I want all of this to occur after the object has already been created and added to the ArrayController.
Here is a fiddle with a simplified example of what I'm trying to achieve.
I am wondering if I'm having problems with scope - I've already tried to bind to the global path (i.e. 'App.objectTwoController.objectOne.param3') to set the binding to. I've also tried to bind directly to the objectOneController (which is not what I want to do, but tried it just to see if it worked) and that still didn't work.
Any ideas on what I'm doing incorrectly? Thanks in advance for taking the time to look at this post.
So in the example below (I simplified it a little bit, but same principles apply)... The method below ends up looking for "objectOne" on "objectTwo" instead of on the "objectTwoController".
var objectTwoController: Em.Object.create({
objectOneBinding: 'App.objectOne',
objectTwoBinding: 'App.objectTwo',
_onSomething: function() {
var objectTwo = this.get('objectTwo');
objectTwo.bind('param2', Em.Binding.from('objectOne.param3'));
}.observes('something')
});
The problem is that you can't bind between two none relative objects. If you look in the "connect" method in ember you will see that it only takes one reference object (this) in which to observe both paths (this is true for 9.8.1 from your example and the ember-pre-1.0 release).
You have few options (that I can think of at least).
First: You can tell the objects about each other and in turn the relative paths will start working. This will actually give "objectTwo" an object to reference when binding paths.
....
objectTwo.set('objectOne', this.get('objectOne');
....
Second: You could add your own observer/computed property that will just keep the two in sync (but it is a little more verbose). You might be able to pull off something really slick but it maybe difficult. Even go so far as writing your own binding (like Transforms) to allow you to bind two non-related objects as long as you have paths to both.
_param3: function(){
this.setPath('objectTwo.param2', this.getPath('objectOne.param3');
}.observes('objectOne.param3')
You can make these dynamically and not need to pre-define them...
Third: Simply make them global paths; "App.objectOneController.content.param3" should work as your binding "_from" path (but not sure how much this helps you in your real application, because with larger applications I personally don't like everything global).
EDIT: When setting the full paths. Make sure you wait until end of the current cycle before fetching the value because bindings don't always update until everything is flushed. Meaning, your alert message needs to be wrapped in Ember.run.next or you will not see the change.

Categories

Resources