I have a problem when navigate between routes with angular 7, for example... i have this code in my app-component.html
<app-navbar *ngIf="currentUser"></app-navbar>
<router-outlet></router-outlet>
<app-footer *ngIf="currentUser"></app-footer>
Everything in the page works, the <router-outlet></router-outlet> have the main component for the page, this component have inside another component, the <app-leftmenu></app-leftmenu> this is the sidebar; originally this was a html-bootstrap 3 template that i segmented for use in angular cli.
Ok the reason for this question is that the SIDEBAR uses jquery for the basic actions like collapse and expand using the next code:
//
// Sidebar categories
//
// Hide if collapsed by default
$('.category-collapsed').children('.category-content').hide();
// Rotate icon if collapsed by default
$('.category-collapsed').find('[data-action=collapse]').addClass('rotate-180');
// Collapse on click
$('.category-title [data-action=collapse]').click(function (e) {
e.preventDefault();
var $categoryCollapse = $(this).parent().parent().parent().nextAll();
$(this).parents('.category-title').toggleClass('category-collapsed');
$(this).toggleClass('rotate-180');
containerHeight(); // adjust page height
$categoryCollapse.slideToggle(150);
});
But not work in angular, only when i reload once time the component if i navigate to other route the sidebar ignore the jquery, but refreshing the page works... how i resolve this... with no refreshing? Thanks for the help!
Presumably because at the time your jQuery code is executed $('.category-collapsed'), there is no such element.
Try jQuery.on(), which allows for later binding: https://api.jquery.com/on/
So this
$('.category-title [data-action=collapse]').click(fn)
becomes (untested)
$(document).on('click', '.category-title [data-action=collapse]', fn)
I would strongly suggest using Angular-Bootstrap instead of a vanilla javascript/jquery solution.
https://ng-bootstrap.github.io/#/home
This library provides a variety of standard UI components - tabbed interfaces, dropdowns, accordion menus etc. all as native Angular components with full TypeScript support.
Related
I am new to HubSpot Platform, with ReactJS background so I'm used to working with components and react-router for navigation;
I came across one problem while building a website template using drag&drop module;
Basically I did not use "menu" or "advanced menu" built-in modules and decided to build navigation myself (reason was: applying custom styling, which is hard with built-in menus);
I built it, which means I have anchor tags which should change the layout after clicked; It should behave like react router: basic components of a website like Header and Footer should not change, but some modules(Components) should change depending on the url location;
I have a folder in design tools which consists of different sections; These sections include different custom modules which then I use in Drag&Drop module that is the main page that is being rendered.
Has anybody had the same problem? If so, how did you manage to make it work ?
Thanks ,
I think I made the issue clear for understanding; If not, let me know and I'll try to explain better.
var addMenu;
componentWillMount: function() {
addMenu = new nw.Menu();
addMenu.append(new nw.MenuItem({
label: 'doSomething',
click: function() {
// doSomething
}
}));
},
contextMenu: function(e) {
e.preventDefault();
addMenu.popup(e.clientX, e.clientY);
},
render: function(){
return <button onClick={this.handleClick} onContextMenu={this.contextMenu}>SomethingUseful</button>
}
This was working fine:
http://jsfiddle.net/musicformellons/ef76gud7/
Now I would like to use MDBootstrap instead of Bootstrap and so I have to alter this jQuery code:
$(document).ready(function () {
$('#navbar').on('show.bs.collapse', function () {
$('#nav-icon4').addClass('open');
});
$('#navbar').on('hide.bs.collapse', function () {
$('#nav-icon4').removeClass('open');
});
});
to work with this side-nav (using my own animated hamburger, see fiddle):
http://mdbootstrap.com/javascript/sidenav/
I can trigger the side-nav with my hamburger by adding these to my hamburger button:
data-activates="slide-out"
class="button-collapse"
But then I loose the animation, since obviously the bootstrap navbar collapse is no longer shown.
How can I have my hamburger animation together with the new side-nav? Probably the cited jQuery code needs to be adjusted completely?!
So following is needed: (1) trigger MD bootstrap sidenav from another CSS button then its default one (2) the hamburger animation should stay 'in sync' with the sidenav. For instance: just using toggle it would probably loose sync as I had similar experiences before: Bootstrap navbar toggle not in sync with dropdown menu
You could use this fiddle as a starting point:
http://jsfiddle.net/musicformellons/rto14vzp/2/
Comments regarding the fiddle:
ignore the JS and CSS resource panel message; i tried adding
mdbootstrap via the resource panel and it did not work whereas
current approach does.
the reference to mdbootstrap (via CDN url) refers to the free part
of mdbootstrap (the side-nav is part of the free package).
The most direct answer to your question is that you need to chain the button animation and sideNav() opening triggers together with one jQuery statement. If you add .nav-icon-line to your spans, that would look like this:
$("#nav-icon4, .nav-icon-line").click(function() {
$("#nav-icon4").addClass('open');
$(".button-collapse").sideNav();
});
There is a lot more going on here that I can't really get into because the source of sideNav() isn't freely available with the framework you are using.
Something else to consider:
You'd need to reset the hamburger animation in the same way by using removeClass(). I'm not really sure how that would work because sideNav() is a black box. From what I can see, sideNav() seems to hide the sidebar when you click outside of it; figure out what function controls that and put $("#nav-icon4").removeClass('open'); into the function.
Codepen example (not fully functional yet, depends on figuing out what's happening inside of sideNav).
My client insists on me using a jQuery plugin I have purchased from CodeCanyon called "Social Wall Stream". It uses isotope to create a dynamic interactive wall with posts from several social media sites.
To include this plugin I have loaded all the required files (after jquery & angular) and created the following directive to load it:
angular.module('app').directive('socialWall', function($timeout){
return {
restrict: 'E',
replace: true,
link: function($scope, element, attrs){
// Load the social stream plugin on our element
angular.element(element).dcSocialStream({
// irrelevant api configuration
});
}
});
Then on the page I want to display the social wall I have added the following html tag to the template:
<social-wall></social-wall>
The plugin renders the social wall like expected and besides the css conflicts with bootstrap it looks good.
Now when I click on a filter (anchor for facebook, twitter, etc.. all the activated social media sites) instead of filtering the isotope layout it redirects the user to the anchor's url (which is "#filter", which gets redirected back to my homepage since it does not exist).
The plugin comes with the following code which should be included before loading to core plugin which enables the isotope layout and the filter toolbar.
/* Isotope minified plugin code */
jQuery(window).load(function(){
var filters = {}, $container = jQuery('.stream');
jQuery('.filter a').click(function(){
var $i = jQuery(this), isoFilters = [], prop, selector, $a = $i.parents('.dcsns-toolbar'), $b = $a.next(), $c = jQuery('.stream',$b);
jQuery('.filter a',$a).removeClass('iso-active');
$i.addClass('iso-active');
filters[ $i.data('group') ] = $i.data('filter');
for (prop in filters){
isoFilters.push(filters[ prop ])
}
selector = isoFilters.join('');
$c.isotope({filter: selector, sortBy : 'postDate'});
return false;
});
});
This code looks like it's intended to stop the redirect (return false) but the $(window).load() is never fired due to angular's routing.
I am using Angular-UI-Router btw, maybe that's relevant.
So I know I need to find some workaround to make the above code angular friendly but I'm not sure how.
What I tried:
Create a directive that waits until the social wall has been loaded and then looks for the element and add a click event listener to it which stops the redirect from happening using preventDefault().
This worked, the directive was fired when the social wall was loaded, but the click event never fired.
Create a directive that stops the redirect (restrict: a). Then add it to the anchors that are added by the jQuery plugin (edited the core).
But these directives never fired, probably something to do with the $compile function. Don't know angular throughout yet. But I know angular is not processing the elements that are being added by the plugin.
I hope I've given enough information and I hope someone knows how I can fix this. Or should I just give up and rewrite the entire code in angular? Don't think the time is worth it though.
Thanks in advance
Okay so I found a solution to this problem. It is not what I wanted but it works so I'll just go with it.
I edited the core of the plugin and removed the href="#target" attribute from the anchors that are being injected by the plugin. And I added a custom class to listen for.
Then in the css I added the following styling to the anchors & the img within it:
cursor: pointer;
to make it look like it did when it had a href.
So now it doesn't redirect anymore and filters the isotope layout like I wanted.
Thanks for the reply Arun P Johny!
I have a custom flipbox which is described in the accepted answer here: JQuery Mobile Custom Flipbox get selected value.
I'm struggling to set the initial value after the page is rendered my 'change-page' function is something like this:
changePage:function (page) {
page.$el.attr('data-role', 'page');
page.render();
$('body').append(page.$el).trigger('create');
$.mobile.changePage(page.$el, {changeHash:false});
}
As I use Backbone.js to manage the views and then I delegate the navigation to jQM.
I basically need to set the initial value of this input text field ( maybe there's a workaround)
Ok I figured this out myself and I'm willing to share the solution:
first of all the change page function is slightly different:
changePage:function (page) {
page.$el.attr('data-role', 'page');
//get rid of everything in the old page.
page.remove();
//render the page again
page.render();
$('body').append(page.$el).trigger('create');
$.mobile.changePage(page.$el, {changeHash:false});
}
the remove call is necessary to get rid of every event listener you had in the old rendered HTML.
In every page that needs init parameters you can specify in the render function this:
render: function(){
....
this.$el.on('pageshow',this.initFields);
....
}
initFields: function(){
// put your jQuery code here (e.g. this.$el.find('foo').val('initValue');
}
please note that this solution as of the jQM documentation is valid up to the 1.5.0 version of jQM, after that the pageshow event will not be triggered anymore.
I'm using jQuery Mobile and Backbone JS for a project. It's mostly working, using jQuery Mobile's event 'pagebeforeshow' to trigger the correct Backbone View. In the Backbone View for that particular jQuery Mobile page, that's where it's doing all the dynamic things needed. Some of the things the views do is pull in certain bits using Underscore's templating system.
This is all great until where I pulling in form bits using the templating system. For example, a set of dynamic radio buttons (which are generated from a Backbone Collection). These radio buttons I want to style up using what jQuery Mobile has to offer. At the moment, jQuery Mobile is not picking up these dynamically injected radio buttons. I solved this issue previously when doing sliders by just calling the jQuery Mobile widget "slider()" method again and it seemed to refresh them... This doesn't seem to be the case with these radio buttons.
In the Backbone View, I tried calling the widget methods again:
$(this.el).find("input[type='radio']").checkboxradio();
$(this.el).find(":jqmData(role='controlgroup')").controlgroup();
I tried them the other way around too, but it seemed I need to do it this way for the grouping styling to work etc. But this just doesn't seem right! ...doing this also caused errors when I clicked on the radio buttons, saying: "cannot call methods on checkboxradio prior to initialization; attempted to call method 'refresh'"?
It seems there should be a way in jQuery Mobile to re-initialize the page or something?! I noticed there is a 'page' widget in the source code.
How does jQuery Mobile handle forms/elements being injected into the DOM after the page is made? Is there a clean way of handling how it makes up the forms? There must be a clean way of calling on the forms to render 'the jQuery Mobile way' without it just relying on data attribute tags in the base HTML?
Any help or insight into this problem would be greatly appreciated... I'm very much on this quest of trying to get Backbone JS and jQuery Mobile to work nicely together.
Many thanks, James
update
Since jQueryMobile beta2 there is an event to do this. .trigger('create') on an element to cause everything inside it to be painted correctly.
Another question that is not a duplicate, but requires an answet I posted over 10 times :)
[old answer]
try .page()
More details in my faq:
http://jquerymobiledictionary.pl/faq.html
Refreshing the whole page worked for me:
$('#pageId').page('destroy').page();
I'm not sure if this helps but when adding dynamic elements I was using .page() in the sucess ajax call itself (example here and here) but I found that it was not working as expected. I found that in the ajax call it's better to refresh the element (if it's a form element) to use these documented methods:
Checkboxes:
$("input[type='checkbox']").attr("checked",true).checkboxradio("refresh");
Radios:
$("input[type='radio']").attr("checked",true).checkboxradio("refresh");
Selects:
var myselect = $("select#foo");
myselect[0].selectedIndex = 3;
myselect.selectmenu("refresh");
Sliders:
$("input[type=range]").val(60).slider("refresh");
Flip switches (they use slider):
var myswitch = $("select#bar");
myswitch[0].selectedIndex = 1;
myswitch .slider("refresh");
and for adding a non-form element use .page()
JQuery Mobile now supports .trigger("create"); which will resolve this for you
Try calling .trigger("create") on the element with the new content.
I needed a way to dynamically refresh a JQM page after it had been initialized. I found that if I removed the data attribute "page" during the "pagehide" event, the next time the JQM page was displayed it was re-initialzed.
$('#testing').live('pagehide', function (e) {
$.removeData(e.target, 'page');
});
$('#pageId').page('destroy').page();
works for entire control groups that are generated, let alone radio input children.
-Mike
It worked for me when I called .trigger('create') on the enclosing div element. See example below:
In .html file:
<div id="status-list" data-role="fieldcontain">
<fieldset data-role="controlgroup">
<legend>Choose as many snacks as you'd like:</legend>
<input type="checkbox" name="checkbox-1a" id="checkbox-1a"/>
<label for="checkbox-1a">Cheetos</label>
</fieldset>
</div>
in .js file:
$("#status-list").trigger('create');
For me only .page() worked (without the .page('destroy')).
E.g.:
$('my-control-group-id').page();
Amnon
I little bit off topic. I wanted to be able to stop jqm from creating first default page div on init as backbone wraps elements in divs anyway. I wanted to dynamically insert pages to the DOM and then call jqm to create its classes and widgets. I finally did this like this:
<head>
<script src="jquery-1.8.3.js"></script>
<script type='javascript'>
$(document).on("mobileinit", function () {
$.mobile.autoInitializePage = false;
}
</script>
<script src="jquery.mobile-1.3.0-beta.1.min.js"></script>
</head>
<body>
....... dynamically add your content ..........
<script type='javascript'>
$.mobile.initializePage()
</script>
</body>
and my hole jqm config (which you put before jqm.js)
$(document).on("mobileinit", function () {
$.mobile.ajaxEnabled = false;
$.mobile.hashListeningEnabled = false;
$.mobile.pushStateEnabled = false;
$.mobile.linkBindingEnabled = false; // delegating all the events to chaplin
$.mobile.changePage.defaults.changeHash = false;
$.mobile.defaultDialogTransition = "none";
$.mobile.defaultPageTransition = "slidedown";
$.mobile.page.prototype.options.degradeInputs.date = true;
$.mobile.page.prototype.options.domCache = false;
$.mobile.autoInitializePage = false;
$.mobile.ignoreContentEnabled=true;
});
So far Backbone and JQM been working fine.
Try use enhanceWithin() method. This should be method of any jQuery object while using jQuery Mobile.