I have a template html page(say Index page) containing a header and three other pages and i want that Header on first two pages but not on third page .Using angularjs routing I am able to have that header on all three pages but cant hide that header from the third page.The pages have different controllers as well .Can anybody help me how to achieve this.
This is not a good practice, not at all! But as your question lacks of code...
You say "The pages have different controllers", so let's say you have PageOneCtrl, PageTwoCtrl and PageThreeCtrl.
If you want to show the header on the page with controllers, let's say: PageOneCtrl and PageTwoCtrl, set a $scope (remember you have to define $scope on that controller first) variable just like:
$scope.showHeader = true;
And in PageThreeCtrl (where you want to HIDE the header element) write
$scope.showHeader = false;
Then in the html you should write:
<header ng-if="showHeader">This is your header content</header>
the ng-if will do the trick, check angularjs documentation for more information: https://docs.angularjs.org/api/ng/directive/ngIf
Doesn't work? Try $rootScope instead of $scope, but watch out! If you use $rootScope then you should declare that variable on every controller.
This is not a good practice, not at all! But as your question lacks of code...
A better practice, and one of the bests in my opinion, would be to use angular-ui-router and set a data attribute to the state (route) with something like
.state('myRoute', {
templateUrl: 'views/my-route-view.html',
controller: 'MyrouteCtrl',
data: {
hideHeader: true;
}
})
, in a .run() function set something like $rootScope.$state = $state (read more about it in the ui.router docs) and then simply: <header ng-if="!$state.current.data.hideHeader">. But I believe you're not an advanced developer to do it :) So keep learning.
Related
Hello guys I'm new to MediaWiki and trying to build my own extension. Using this extension I'm trying to show some content blow page heading but only to a page specific to a category.
For that, I'm using two hooks:
onArticleViewHeader ( To add my HTML content below the page heading)
onOutputPageMakeCategoryLinks (To get all the category of page being loaded)
From the first hook, I'm able to show my content using the following code:
public static function onArticleViewHeader( &$article, &$outputDone, &$pcache ) {
$article->getContext()->getOutput()->addHTML("Printed from a hook");
}
The above code prints the HTML below every page heading but I want to load HTML only to a specific page category. So for that, I'm trying to load the category and I'm just trying to call my first hook only if the category gets caught.
public static function onOutputPageMakeCategoryLinks( &$out, $categories, &$links ) {
foreach($categories as $category){
if($category=="my_page_category"){
MyExtentionClass::onArticleViewHeader();
}
}
}
I know I'm calling the hook in a bad manner which is not correct. But I just wanted to call my 1st hook 'onArticleViewHeader' from inside of my 2nd hook so that I can print my HTML only to a page with a specific category.
Just use $article->getPage()->getCategories() in the header hook.
Haven't really got the exact solution of the question I asked but has got the way out to solve the problem I have been facing.
I just tried getting the current categories in the "onArticleViewHeader" itself by using some of MediaWiki's global variables.
global $wgOut;
$title = Title::newFromText( $wgOut->getPageTitle() );
$categories = $title->getParentCategories();
if(isset($categories['Category:my_cat_name']){
//formed my logic here
}
This might help some other people facing this kind of issue.
I have a page partial that is supposed to render inside a ContentArea when the page is added there. This works perfectly, but now I have two different ContentAreas on two different pages and I want the same child page added to those to render different on each parent page.
I get that I could in some way use a Tag when rendering the partial to differentiate between the ContentAreas:
#Html.PropertyFor(m => m.MyBlockProperty, new { Tag = RenderingTags.Sidebar })
#Html.PropertyFor(m => m.MyContentArea, new { Tag = RenderingTags.Sidebar })
But then, in my SomePage.cshtml (which is my partial view), do I get a varaible or something here so I know which Tag was asked for? Or is there some naming convention like SidebarSomePage.cshtml so that I can define multiple partial templates? Do I have to create a controller to deal with this? It seems unneccessary to me, I just want to change the html a bit depending on page...
Create a PartialContentController<T> and then use the TemplateDescriptorAttribute to specify the tags you wan't to use. Then use PropertyFor as Johan explained in the view.
From the EPiServer documentation
The template you choose to render a content instance depends on the specific context such as channel and tagging. For a template to be automatically registered it has to implement EPiServer.Web.IRenderTemplate (where T states which model it can render). If you use a base class for your template like PageBase, ContentControlBase, BlockControlBase, PageController, PartialContentController or BlockController, then you do not need to explicitly implement the interface because that is done by the base class. In addition, you can use the TemplateDescriptorAttribute to specify more details about the template such as tags and inheritance, more information on that topic later.
I'm pretty sure you can access the tag from the ViewData dictionary in your view (or controller) like this:
#ViewData["Tag"]
You can also pass any other setting to the view
#Html.PropertyFor(m => m.MyContentArea, new { Tag = RenderingTags.Sidebar, RenderThisPartialDifferently = true, ShowHeading = false })
And then access them:
#ViewData["RenderThisPartialDifferently"]
#ViewData["ShowHeading "]
And then you have the option to have a controller in between and render a completely different view.
Pretty sure there is a naming convention for tag views as well. What I do know for sure though, is that you can put a view with the same name as the tag in /shared/displaytemplates. But that's not what you're asking for now.
Also addition to all answers, you can use template registrator to register additional templates for specific tags.
[ServiceConfiguration(typeof(IViewTemplateModelRegistrator))]
public class TemplateCoordinator : IViewTemplateModelRegistrator
{
public void Register(TemplateModelCollection viewTemplateModelRegistrator)
{
viewTemplateModelRegistrator.Add(typeof(MyBlock), new TemplateModel
{
Tags = new[] { RenderingTags.Sidebar },
AvailableWithoutTag = false,
Path = BlockPath("Some-Other-Template.cshtml")
});
}
}
This will make sure that if block is rendered "inside" RenderingTags.Sidebar context (for instance via Html.PropertyFor(...., new { tag = RenderingTags.Sidebar })) file Some-Other-Template.cshtml will be used.
AlloyTech has sample code there.
I'm starting to learn angularJS better, and I've noticed that AngularJS tries to make strong emphasis on separating the view from the controller and encapsulation. One example of this is people telling me DOM manipulation should go in directives. I kinda got the hang of it now, and how using link functions that inject the current element allow for great behavior functionality, but this doesn't explain a problem I always encounter.
Example:
I have a sidebar I want to open by clicking a button. There is no way to do this in button's directive link function without using a hard-coded javascript/jquery selector to grab the sidebar, something I've seen very frowned upon in angularJS (hard-coding dom selectors) since it breaks separation of concerns. I guess one way of getting around this is making each element I wish to manipulate an attribute directive and on it's link function, saving a reference it's element property into a dom-factory so that whenever a directive needs to access an element other than itself, it can call the dom-factory which returns the element, even if it knows nothing where it came from. But is this the "Angular way"?
I say this because in my current project I'm using hard-coded selectors which are already a pain to mantain because I'm constantly changing my css. There must be a better way to access multiple DOM elements. Any ideas?
There are a number of ways to approach this.
One approach, is to create a create a sidebar directive that responds to "well-defined" broadcasted messages to open/close the sidebar.
.directive("sidebar", function(){
return {
templateUrl: "sidebar.template.html",
link: function(scope, element){
scope.$root.$on("openSidebar", function(){
// whatever you do to actually show the sidebar DOM content
// e.x. element.show();
});
}
}
});
Then, a button could invoke a function in some controller to open a sidebar:
$scope.openSidebar = function(){
$scope.$root.$emit("openSidebar");
}
Another approach is to use a $sidebar service - this is somewhat similar to how $modal works in angularui-bootstrap, but could be more simplified.
Well, if you have a directive on a button and the element you need is outside the directive, you could pass the class of the element you need to toggle as an attribute
<button my-directive data-toggle-class="sidebar">open</button>
Then in your directive
App.directive('myDirective', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
angular.element('.' + attrs.toggleClass).toggleClass('active');
}
};
}
You won't always have the link element argument match up with what you need to manipulate unfortunately. There are many "angular ways" to solve this though.
You could even do something like:
<div ng-init="isOpen = false" class="sidebar" ng-class="{'active': isOpen}" ng-click="isOpen = !isOpen">
...
</div>
The best way for directive to communicate with each other is through events. It also keeps with the separation of concerns. Your button could $broadcast on the $rootScope so that all scopes hear it. You would emit and event such as sidebar.open. Then the sidebar directive would listen for that event and act upon it.
I want to implement AngularJS's ng-include statement into my website to reduce code redundancy, but having trouble getting it to fully work. Currently, my index.html page is calling pageLayout.html My index.html is calling pageLayout.html successfully, but when adding a <h1> tag in index.html I cant put it on top of the pageLayout.html content that I call. Does anyone have any ideas?
Here is the link: http://plnkr.co/edit/uarelZgzmITJXg2pYXfg?p=preview
I have also tried using a directive like the following: http://plnkr.co/edit/VmAO47l7RMXTGYYFFgLB?p=preview but still having issues.
Thanks!
The transclusion strategy is set to element not to true so you can not insert extra content.
Moreover the content is wiped everytime the template value changes
And using transclusion with ngInclude does not make sense
I would rather use a directive with transclusion (or bind the title) if you want to avoid code duplication, something like
directive('pageContainer',function(){
return {
template:'<div class="divSize" ><h1>{{title}}</h1><div ng-transclude></div></div>',
scope:{
title:"#"
}
}
})
In a SPA, using a navigation framework such as Sammy.js, how could I use in page named anchors for in-page navigation?
e.g. Say I have a route like localhost/myapp/#/somerecord/1 where the application loads somerecord with id = 1.
However somerecord is really complicated and long. I want to be able to jump to a certain section using a named anchor.
Say an article element is defined like <article id=section-d> ... </article> and I just link to like <a href=#section-d>Section D</a> it technically works, but the URL reads like localhost/myapp/#section-d, this breaks the navigation stack. Hitting the Back button takes me back to localhost/myapp/#/somerecord/1 and without jumping back to the top.
The preferred action would be to either jump back to the top or to the previous page. Any ideas on how to accomplish this?
Effectively, you have to define your URL as a regular expression, and allow an optional bookmark hash at the end of it; something like:
get(/#\/somerecord\/(\d+)(#.+)?/, function() {
var args = this.params['splat'];
var recordId = args[0];
var articleId = args[1];
});
This should match any of the following routes:
#/somerecord/1
#/somerecord/1# (treated as if there is no article id)
#/somerecord/1#section-d (articleId = '#section-d')
You should then be able to use the articleId to find the matching element and manually scroll. e.g. in the last route above, using jQuery you could do something like:
var $article = $(articleId);
$(document.body).animate({ scrollTop: $article.offset().top });
});
I've just written up a more comprehensive article about this (using Durandal), if you're interested: http://quickduck.com/blog/2013/04/23/anchor-navigation-durandal/
Edit
Link is dead. The article available here http://decompile.it/blog/2013/04/23/anchor-navigation-durandal/
I've had the same problem using durandal with sammy.js. Basically, you have to create a (invisible) route for each anchor you want on your page. See a post from me about the solution I found: http://papamufflon.blogspot.de/2013/04/durandal-scrollspy.html