if.bind on a repeater - doesn't work in Edge & IE - microsoft-edge

I have the following html part of code:
<li repeat.for="route of router.navigation" style="border: 0px;" if.bind="showNav(route)">
<a href.bind="route.href" if.bind="!route.settings.nav">
${route.title}
</a>
<a href="javascript:;" if.bind="route.settings.nav">
${route.title}
</a>
<ul if.bind="route.settings.nav" class="dropdown-menu">
<li repeat.for="menu of route.settings.nav" class="ul-menu">
<a href.bind="menu.href">${menu.title}</a>
</li>
</ul>
</li>
In Opera, Chrome this code works fine, but in IE & Edge doesn't work - I don't see this HTML-part.
Problem is in the following statement (in the first line):
if.bind="showNav(route)"
If I deleted it, I can see my navigation menu in Edge & IE also.
Code for showNav:
showNav(row) {
if (!row.config.role) {
return true;
}
this.currentUserName = localStorage.getItem("token_user");
var currentUser = localStorage.getItem("token_role");
var role = row.config.role.includes(currentUser);
return role;
}
If I add in showNav
console.log(row);
It logs undefined in Edge & IE, but in Opera & Chrome I see the full necessary value.
I work with Aurelia framework, so route.navigation goes from ts-file and has the necessary value.
What could be the problem?

The github issue from #jesse-de-bruijne is different, that if.bind and repeat.for are not on the same DOM element. Furthermore, that issue was FIXED long time ago. But anyway, the show.bind purposed by Jesse works.
The real issue is that you are using if.bind and repeat.for on exact same DOM element, which is not supported by Aurelia due to uneven behavior from browsers. Aurelia documentation has not yet addressed this.
Besides the show.bind fix, you can also use template element (which will result to no extra DOM wrapper actually) to seperate repeat.for and if.bind.
<template> <!-- the top level template in your html file -->
...
<template repeat.for="route of router.navigation">
<li style="border: 0px;" if.bind="showNav(route)">
...
</li>
</template>
...
</template>
FYI: Repeat, with and if are called template controllers. They bind before other bindings. You cannot use multiple template controller attributes on the same dom element (because of different behavior among browsers).
The above comment is from Aurelia core member jdanyow on one of my issues.
https://github.com/aurelia/templating-resources/issues/252
Indeed, different browsers sort the HTML attributes differently. That's why your code works on some browsers but not all.

Try using a show.bind instead, if.bind has had some trouble with a repeater on the same line.
For example: https://github.com/aurelia/templating-resources/issues/84
If you do need to use an if.bind, for performance reasons for example, try putting a div child in the repeater containing said if.bind.

Related

Polymer - how to get the ID from paper-Input?

[Dart+Polymer]
Hello,
I have PaperInput elements in a Polymer dom-repeat template. So, there are several, so on the #Listen I try to get the id, but it only retrieves id="labelAndInputContainer" (no matter what I do in the template).
Is there some trick to this? I've tried "everything" - over the past half a day!
Here is my HTML:
<template is="dom-repeat" items={{rgetThem}}>
<paper-card heading={{yyyy(item)}} >
<div class="card-content" >
<p style="color:red">ID:{{getID(item)}}</p>
<paper-input on-change="onchangepassword"
label='Password'
id={{getID(item)}}
floatingLabel>
</paper-input>
</div>
And the listener:
#Listen ('onchangepassword')
void onchangepassword(Event custEvent, var t) {
IronInput PI=custEvent.target;
Element yy=PI.parent;
String id=yy.id;
}
Any suggestions MOST welcome.
Thanks
Steve
You could try
Element yy=PI.parent.closest('paper-input');
The problem you're facing is paper-element encapsulates an iron-input element wrapped in div elements. Finding the closest paper-input will find the paper-input which the iron-input is encapsulated in, since that's the nearest one. I'm sure there are other ways to do it, but this works for me. In fact you could just do
Element yy=PI.closest('paper-input');
which will work just as well.
UPDATE:
Upon seeing the comment about dom-repeat event models, it occurs to me you may want a more Polymer Dart specific documentation link.
https://github.com/dart-lang/polymer-dart/wiki/data-binding-helper-elements#handling-events-in-dom-repeat-templates
As was suggested
model.item.id
And I'm not going to take credit for the updated part of my answer except the Dart specific link.

Get children of an XHPChild

I am trying to move my website to Hack and XHP, of course. Below is a structure of what code structure I want to achieve:
<ui:backstageHeader>
<ui:backstageHeader-navItem href="/">stories</ui:backstageHeader-navItem>
<ui:backstageHeader-navItem href="/story/send">send a story</ui:backstageHeader-navItem>
<ui:backstageHeader-navItem href="/aboutus">support</ui:backstageHeader-navItem>
</ui:backstageHeader>
(Note: :ui:backstageHeader-navItem basically renders to <a href={$this->:href}>{$this->getCHildren}</a> so there is not need to attach its class here.)
Below is the code for :ui:backstageHeader:
final class :ui:backstageHeader extends :ui:base {
attribute :div;
children (:ui:backstageHeader-navItem)*;
protected function compose() {
$dom =
<section class="backstage-header">
<div class="container">
<div class="cell-logo">
<a href="/">
<span class="no23-logo-white"></span>
</a>
</div>
<div class="cell-navigation">
</div>
<div class="cell-account">
<div class="cell-login">
<div id="siteNav-login">Autentificare</div>
</div>
</div>
</div>
</section>;
$mainContainer = $dom->getChildren("div")[0];
$cellNavigation = $mainContainer->getChildren("div")[1];
$navItems = <ul class="main-navigation"></ul>;
foreach($this->getChildren() as $child) {
$navItems->appendChild(<li>{$child}</li>);
}
$dom->appendChild($navItems);
return $dom;
}
}
I used the Terminal to debug my code using hhvm -m d <file.php>, and everything was alright there; however, when I get to my browser, I get 500 error header. This is what the log says:
Catchable fatal error: Hack type error: Could not find method getChildren in an object of type XHPChild at /var/www/res/ui/backstage-header.php line 25
The error comes from
$cellNavigation = $mainContainer->getChildren("div")[1];
But, somehow, I need to append ul.main-navigation to div.cell-navigation from my section.backstage-header.
How can I do it?
Don't structure your code this way. Built it up from the inside out, so that you don't have to do a ton of unreadable getChildren calls looking for specific children. Those calls are super hard to read, and super inflexible when you change the structure of your XHP. You wouldn't do something like node.firstChild.lastChild.lastChild.firstChild in the JS DOM, would you? No, there's a better way in JS, to find things by class or ID; in XHP, you can just build it up the right way in the first place!
I'd give you an example of this, but it doesn't look like you actually use $mainContainer or $cellNavigation, so you can just remove those two problematic definitions.
As an aside, you really shouldn't be getting your type errors as catchable fatals from HHVM; this is a last resort sort of check. Try running the hh_client checker directly, maybe even showing its result in your IDE; it will give you a much faster iteration cycle, and much more information than HHVM provides.
From my experience, appendChild is very prone to human error. It's easier to do something like:
$items = (new Vector($this->getChildren()))->map($child ==> <li>{$child}</li>);
return <div id="container">{$items}</div>;
If you want to wrap the children in <li />.
Not sure if that will work but it will be close.
Pro tip: You can assign variables from within an XHP tree.
$root =
<div>
{$child = <span>
Text children
</span>}
</div>;
Now $child is already set to the <span> element.

Making first mobile Safari tap a 'clickable action'

I have seen variations on the theme, but no clear answer. Basically I want an AngularJS Directive that registers a click and inserts extra content into a page, and then scrolls down a bit to make the new content visible. Here is the HTML
<li class="btn btn-default" ng-show="resto.link !== 'none'">
<p scroll-down onclick="void(0)">
Full review
<span class="glyphicon glyphicon-chevron-right right"></span>
</p>
</li>
</ul>
<div class="row">
<div class="col-xs-12" ng-bind-html="fullReview">
</div>
</div>
The onlick part is an Apple suggestion, that seems not to work.
And then I have:
.directive 'scrollDown', () ->
restrict: 'A'
link: (scope, $elm, attrs) ->
$elm.on 'click', (e) ->
e.preventDefault()
scope.getFullReview () ->
console.log "Scrolling'
$("body").animate
scrollTop: $elm.offset().top - 100
, "slow"
getFullReview() updates the model after an AJAX call, and then runs the callback.
This works fine in Chrome but not on the iOS simulator - basically a first tap makes the page move (but without triggering the console log - I think this is the URL bar regrowing) and a second is needed to trigger the Directive's link function. I have also installed fastclick as that was mentioned in some posts, but it did not help.
Need ideas :-) (Even some code that would tell me what event is being triggered by safari)
OK, Wow, I do not understand why, but the html above was the last markup on the page, so all of this was happening at the bottom of the screen. When I added some extra margin to the <ul> element, everything started working perfectly!! Bug in Safari?

Meteor: In template rendered event selecting multiple elements to become draggable not working

Update 2: A The following repo on github shows the problem.
Update 1: Calling #firstNode in Template.editor.rendered returns <div class="editor"></div>.
I have the following template:
<template name="editor">
<div class="editor">
{{#each objects}}
<div class="object">{{content}}</div>
{{/each}}
</div>
</template>
The data is provided by iron-router in the data callback.
The coffeescript for my template:
Template.editor.rendered = ->
#findAll('.object').draggable()
When I go into my browser and try to drag one of the objects I get the text selection cursor and begin to select the text with the div instead of the object being dragged. So what is wrong and how can I get the drag and drop to work?
The drag and drop functionality is being provided by jquery-ui. Which is installed as a smart package.
Also feel free to edit the title of this post as I had a tough time coming up with one that made sense
The solution I found was to abstract <div class="object">{{content}}</div> into a seperate template like so:
<template name="object">
<div class="object">{{content}}</div>
</template>
Then change
Template.editor.rendered = ->
#findAll('.object').draggable()
to
Template.object.rendered = ->
#findAll('.object').draggable()
As stated in meteorpedia.

I got jquery-ui sortable working with meteor templates, but is it a bad hack?

I'm trying to use jquery-ui sortable with nested templates in Meteor, as follows. Here are the two templates in question:
<template name="activityEditor">
{{! the main activity editor view }}
<div class="activity-editor">
<input type="text" name="title" class="input-xxlarge" value="{{info.title}}" placeholder="Type a title here...">
<div class="activity-steps">
{{#each info.steps}}
{{>activityStepEditor}}
{{/each}}
</div>
</div>
</template>
<template name="activityStepEditor">
{{! the container view for each step editor }}
<div class="activity-step" data-id="{{_id}}">
<div class="order">{{order}}</div>
{{!....stuff...}}
</div>
</template>
and the template code (using coffeescript):
_.extend Template.activityEditor, {
# ...stuff...
rendered: ->
$(".activity-steps").sortable {
items: '.activity-step'
handle: '.order'
update: ->
stepIds = ($(el).attr('data-id') for el in $('.activity-step'))
$('.activity-steps').empty() #this must be done in order to steps to re-render properly
Lab.Activity.reorderSteps stepIds
}
$(".activity-steps").disableSelection()
}
The only way I can get this code to work and properly rerender the order is by emptying the container of my sortable elements right after they update with $('.activity-steps').empty(). I've tried cancelling the update event and forcing a rerender by changing another variable watched in the context, but any change causes Exception from Meteor.flush(): undefined after which I can't rerender anything until page reload.
This seems to work, and everything rerenders great. So my question is: is there any reason why I shouldn't do this? Is there a better, standard practice way to handle the sortable that I'm not seeing?
In the near future there'll be a better way to do it, as Meteor team is developing its new rendering engine: http://youtube.com/watch?v=ISNEhPG0wnA
(in this video, Avital Oliver shows exactly a way to do it without redrawing the screen: the object in the list is actually moved on all clients)
See this Meteor's Github Wiki entry for more technical info:
http://github.com/meteor/meteor/wiki/New-Template-Engine-Preview
While that's not officially published, if you need it right now, you could try Nazar Leush's approach:
http://github.com/nleush/meteor-todos-sortable-animation
He also published a working example here: http://todos-dnd-animated.meteor.com

Resources