ui-router state reverts to parent, and ui-view is cleared...why? - angular-ui-router

I'm implementing tabs in AngularJS, using ui-router. The problem is once I click on any of the links that are created, the state momentarily changes (as seen in the url) as well as ui-view is populated for a brief moment, then disappears. There are no styles associated with ui-view. Any ideas...?
The issue is in clicking a link on the ReportParent view (the parent).
Controller:
function ReportParentController($scope, $http, $q, $interval, ReportParentService, $stateParams, $state) {
var vm = this;
vm.dataArray = [];
vm.CustomerID = $stateParams.CustomerID;
vm.TabList = [];
ReportParentService.getReportList(vm.CustomerID).then(function (response) {
vm.TabData = response;
updateUrlValue(vm.TabData);
createTabList(vm.TabData);
});
function updateUrlValue(data) {
for (CurrentTabItem = 0; CurrentTabItem < data.length; CurrentTabItem++) {
data[CurrentTabItem].Url = "details.reportParent." + data[CurrentTabItem].NameNoSpaces + "Report";
}
}
function createTabList(data) {
for (CurrentTabItem = 0; CurrentTabItem < data.length; CurrentTabItem++) {
vm.TabList.push({ id: CurrentTabItem, Name: data[CurrentTabItem].Name, NameNoSpaces: data[CurrentTabItem].NameNoSpaces, Url: data[CurrentTabItem].Url });
}
}
}
View:
<div class="project-tab-menu ui right secondary menu" style="margin-right:1em;">
<a ng-repeat="Tab in vm.TabData" ui-sref={{Tab.Url}}>{{Tab.Name}}</a>
</div>
<div ui-view ></div>
Routing:
.state('details.reportParent.WindowsServerReport', {
url: '/windowsServerReport',
views: {
'#details.reportParent': {
templateUrl: 'Routing/WindowsServerReport',
controller: 'WindowsServerReportController',
controllerAs: 'vm',
},
},
})
.state('details.reportParent', {
url: '/reportParent',
templateUrl: 'Routing/ResultReportParent',
controller: 'ReportParentController',
controllerAs: 'vm'
});`

Turns out it's necessary to point to a ui-view on the parent, and using a url messes this up. Replace the details.reportParent route with the following
.state('details.reportParent', {
views: {
'resultsTab#details': {
templateUrl: 'Routing/ResultReportParent',
controller: 'ReportParentController',
controllerAs: 'vm'
},
},
});
Also make sure that in the parent view, you're putting data into a ui-view in this case <div ui-view ='resultsTab'></div>

Related

How to go to another page by clicking on a row of a html-table?

I have a MVC-application.
I want to go to the DetailInfo page by clicking on the row of the Index page.
How do you do that?
Part of Index.cshtml
#for (var item = 0; item < Model.Count; item++)
{
<tbody>
<tr ##click="detailInfo(#Model[item].Id)">
<td>#Html.DisplayFor(Model => Model[item].Message)</td>
logmessages.js
const app = Vue.createApp({
// data, functions
methods: {
rowClick(item) {
console.log('Dit is regel: ' + item)
},
detailInfo(id) {
$.ajax({
type: "POST",
url: '<% = Url.Action("DetailInfo", "Home") %>',
data: { id = id },
succes: function (data) {
console.log(id + "is posted.");
}
})
},
}
})
app.mount('#app')
... and in the HomeController
[HttpPost]
public IActionResult DetailInfo(int id)
{
var dto = _logboekService.GetLogBerichtById(id);
var model = _mapper.Map<LogBerichtDto, LogBerichtModel>(dto);
return View(model);
}
To go to another page, you could use router.push({ path: 'home' }) as stated in the vue-router documentation.

how to load a partial view inside an anchor tag which has been generated via Ajax

I have a form with a dropdownlist. When selecting an option, I make an ajax call to dynamically add a list of links in the view. When I click on one of the links, I want to update the existing page with a partial view returned by the PostListSubCategory() method.
Currently, clicking on one of the links does a redirect and shows the partial view in a new page. How can I update the the existing page?
<script language="javascript" type="text/javascript">
function GetSubCategory(_categoryId) {
var procemessage = "<a='0'> Please wait...</a>";
$("#SubCategoryID").html(procemessage).show();
var url = "/Posts/GetSubCategoryById/";
$.ajax({
url: url,
data: { categoryid: _categoryId },
cache: false,
type: "POST",
success: function (data) {
var markup = "";
for (var x = 0; x < data.length; x++) {
var num = data[x].Text;
markup += "<a href='/posts/postlistsubcategory?subcategoryid=" + data[x].Text + "'>" + data[x].Text + "</a><br />";
// markup += "<a href=" + Url.Action("postlistsubcategory", new { subcategoryid = num });
}
$("#SubCategoryID").html(markup).show();
},
error: function (reponse) {
alert("error : " + reponse);
}
});
$.ajax({
url: "/Posts/PostListCategory",
data: { categoryid: _categoryId },
cache: false,
type: "POST",
success: function (data) {
$("#postList").html(data).show();
},
error: function (reponse) {
alert("error : " + reponse);
}
});
}
</script>
#using (Html.BeginForm())
{
#Html.ListBoxFor(m => m.CategoryModel, new SelectList(Model.CategoryModel, "CategoryId", "Name"), new { #id = "ddlcategory", #style = "width:200px;", #onchange = "javascript:GetSubCategory(this.value);" })
<br />
<br />
<div id="SubCategoryID" name="SubCategoryID" style="width: 200px"></div>
<br /><br />
}
In the controller
public PartialViewResult PostListSubCategory(string subcategoryid)
{
if (subcategoryid == null)
{
return PartialView(db.Posts.ToList());
}
return PartialView("PostList", db.Posts.Include(i => i.SubCategory).Where(p => p.SubCategory.Name == subcategoryid));
}
You currently dyamically generating links with an href attribute so clicking on them will do a redirect. You need to handle the click event of those links using event delegation and then use ajax to update the existing DOM. There a some other bad practices in your code and I suggest you use the following
#using (Html.BeginForm())
{
// no need to override the id attribute and use Unobtrusive Javascript (don't pollute markup with behavior)
#Html.ListBoxFor(m => m.CategoryModel, new SelectList(Model.CategoryModel,"CategoryId", "Name"))
}
<div id="SubCategoryID"></div> // no point adding a name attribute
<div id="postList"></div>
var subcategories = $('#SubCategoryID');
$('#CategoryModel').change(function() {
var url = '#Url.Action("GetSubCategoryById", "Posts")'; // don't hard code url's
var category = $(this).val();
subcategories.empty(); // clear any existing links
$.post(url, { categoryid: category }, function(data) { // this could be a GET?
$.each(data, function(index, item) {
subcategories.append($('<a></a>').text(item).attr('href','#').addClass('subcategory')); // see note below
});
});
});
Note: Since your ajax only needs one property to generate the links (the value to display in the link), then your GetSubCategoryById() should be returning IEnumerable<string> not a collection of complex objects (you current code suggest your returning other data which you never use). If you do need to return a collection of objects, then change the above to use .text(item.Text). The above code will generate
.....
for each item you return. Then add an additional script to handle the .click() event of the links (since the links are dynamically added, you need event delegation using the .on() method)
var posts = $('#postList');
$('#SubCategoryID').on('click', '.subcategory', function() {
var url = '#Url.Action("postlistsubcategory", "posts")';
var subcategory = $(this).text();
posts.load(url, { subcategoryid: subcategory });
});

angular-slick carousel not working when using promise

This is driving my crazy, the first angular-slick is not working but the second is just fine, any idea what is going on?
I created a plunkr (in case someone is looking for an example in the future), but my problem is very odd because in my code/realproject is not working so I don't know what the hell is going on, anyway! here is the plunkr: http://plnkr.co/edit/URIbhoVpm1OcLSQqISPs?p=preview
I think the problem is related to the DOM because maybe angular needs to create the html before the carousel is render, I don't know... :(
This is the outcome:
https://db.tt/noc0VgGU
Router:
(function() {
'use strict';
angular
.module('mgxApp.landing')
.config(configFunction);
configFunction.$inject = ['$routeProvider'];
function configFunction($routeProvider) {
$routeProvider.when('/', {
templateUrl: 'app/landing/landing.html',
controller: 'homeCtrl',
controllerAs: 'hC'
});
}
})();
Controller:
(function() {
'use strict';
angular
.module('mgxApp.landing')
.controller('homeCtrl', homeCtrl);
homeCtrl.$inject = ['modalFactory', 'channelFactory'];
function homeCtrl(modalFactory, channelFactory) {
var hC = this;
hC.openAuthModal = modalFactory.openAuthModal;
hC.activeChannels;
channelFactory.allActiveChannels().then(function(activechannels){
console.log(activechannels);
hC.activeChannels = activechannels;
});
hC.w = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
hC.breakpoints = [
{
breakpoint: 768,
settings: {
slidesToShow: 2,
slidesToScroll: 2
}
}, {
breakpoint: 480,
settings: {
slidesToShow: 1,
slidesToScroll: 1
}
}
];
}
})();
HTML VIEW:
// NOT WORKING
<slick class="slider single-item" responsive="hC.breakpoints" slides-to-show=3 slides-to-scroll=3>
<div ng-repeat="channel in hC.activeChannels">
{{channel.get("username")}}
</div>
</slick>
// Working fine
<slick class="slider single-item" current-index="index" responsive="hC.breakpoints" slides-to-show=3 slides-to-scroll=3>
<div ng-repeat="i in hC.w">
<h3>{{ i }}</h3>
</div>
</slick>
Factory and Promise:
(function () {
'use strict';
angular
.module('mgxApp.channel')
.factory('channelFactory', channelFactory);
channelFactory.$inject = ['$rootScope', '$q'];
function channelFactory($rootScope, $q) {
var service = {
allActiveChannels : allActiveChannels
};
return service;
function allActiveChannels() {
var deferral = $q.defer();
var User = Parse.Object.extend("_User");
var query = new Parse.Query(User).limit(10);
query.find({
success: function(users) {
console.log(users);
/*for (var i = 0; i < users.length; i++) {
console.log(users[i].get("username"));
}*/
deferral.resolve(users);
},
error: function(error) {
console.warn(error);
deferral.reject();
}
});
return deferral.promise;
}
}
})();
My working code
<div tmob-slick-slider sliderData="" dynamicDataChange="true" class="utilHeightImg marqueeContainer">
<slick id="productCarousel" class="slider" settings="vm.slickAccessoriesConfig" data-slick='{"autoplay ": true, "autoplaySpeed": 4000}'>
<!-- repeat='image' -->
<div ng-repeat="slideContent in vm.slides track by $index" >
<div bind-unsafe-html="slideContent" ></div>
</div>
<!-- end repeat -->
</slick>
</div>
you have to write a directive to reinitialize the slider
angular.module('tmobileApp')
.directive('tmobSlickSlider',['$compile',function ($compile) {
return {
restrict: 'EA',
scope: true,
link: function (scope, element, attrs) {
scope.$on('MarqueesliderDataChangeEvent', function (event, data) {
$compile(element.contents())(scope);
});
}
};
}]);
Write this in your controller
hc.selectView=false; // make this hc.selectView=true when your promise get resolve
$scope.$watch('hc.selectView', function(newValue, oldValue) {
$scope.$broadcast('MarqueesliderDataChangeEvent');
});
I ended up using this solution:
Angular-slick ng-repeat $http get
I'd suggest you to use ng-if on slick element. That will only load slick directive only when data is present just by checking length of data.
Markup
<slick ng-if="ctrl.products.length">
<div ng-repeat="product in ctrl.products">
<img ng-src="{{product.image}}" alt="{{product.title}}"/>
</div>
</slick>

ember model find query with params doesn't display on pagination

2I have an Ember app which connects to an api from where it gets articles. I make use of pagination to get 10 articles per request. This works. But now I wanted to add sorting to the request. I implemented this by using the extra parameter in the store.find.
However, for some reason if I use the 'return this.store.find('article', params);' instead of 'return this.store.find('article');' new articles (still requested and added correctly to the store!) in the getMore function are not beiing displayed or rendered. But when i remove the params parameter from store.find in model, it does work. What could be the case here?
templates/articles.hbs
<script type="text/x-handlebars" data-template-name="articles">
{{#each itemController="article"}}
<div class="item">
//...
</div>
{{/each}}
</script>
routes/articles.js
import Ember from 'ember';
export default Ember.Route.extend(Ember.UserApp.ProtectedRouteMixin, {
model: function(params) {
var params2 = {page: 1, per_page: 10, sort: params.sort};
return this.store.find('article', params2);
},
setupController: function(controller, model) {
controller.set('content', model);
},
actions:{
//...
},
getMore: function() {
// don't load new data if we already are
//if (this.get('loadingMore')) return;
//this.set('loadingMore', true);
var meta = this.store.metadataFor("article");
if (meta.hasmore) {
var controller = this.get('controller'),
nextPage = controller.get('page') + 1,
perPage = controller.get('perPage'),
sorting = controller.get('sort'),
items;
var params = {page: nextPage, per_page: perPage, sort: sorting};
this.store.findQuery('article', params).then(function (articles) {
controller.set('page', controller.get('page') + 1);
//this.set('loadingMore', false);
});
}
else{
$('#pagination_spinner').hide();
}
},
queryParamsDidChange: function() {
this.refresh();
}
}
});
controllers/articles.js
import Ember from 'ember';
var ArticlesController = Ember.ArrayController.extend({
itemController: 'article',
queryParams: ['sort'],
sort: 'rating',
page: 1,
perPage: 10
});
export default ArticlesController;
views/articles.js
import Ember from 'ember';
export default Ember.View.extend({
didInsertElement: function(){
//this.scheduleMasonry();
this.applyMasonry();
// we want to make sure 'this' inside `didScroll` refers
// to the IndexView, so we use jquery's `proxy` method to bind it
//this.applyMasonry();
$(window).on('scroll', $.proxy(this.didScroll, this));
},
willDestroyElement: function(){
this.destroyMasonry();
// have to use the same argument to `off` that we did to `on`
$(window).off('scroll', $.proxy(this.didScroll, this));
},
// this is called every time we scroll
didScroll: function(){
if (this.isScrolledToBottom()) {
$('#pagination_spinner').addClass('active');
this.get('controller').send('getMore');
}
},
scheduleMasonry: (function(){
Ember.run.scheduleOnce('afterRender', this, this.applyMasonry);
}).observes('controller.model.#each'), //TODO check
applyMasonry: function(){
$('#pagination_spinner').removeClass('active');
var $galleryContainer = $('#galleryContainer');
$galleryContainer.imagesLoaded(function() {
// check if masonry is initialized
var msnry = $galleryContainer.data('masonry');
if ( msnry ) {
msnry.reloadItems();
// disable transition
var transitionDuration = msnry.options.transitionDuration;
msnry.options.transitionDuration = 0;
msnry.layout();
// reset transition
msnry.options.transitionDuration = transitionDuration;
} else {
// init masonry
$galleryContainer.masonry({
itemSelector: '.item',
columnWidth: 0,
"isFitWidth": true
});
}
});
},
destroyMasonry: function(){
$('#galleryContainer').masonry('destroy');
},
// we check if we are at the bottom of the page
isScrolledToBottom: function(){
var distanceToViewportTop = (
$(document).height() - $(window).height());
var viewPortTop = $(document).scrollTop();
if (viewPortTop === 0) {
// if we are at the top of the page, don't do
// the infinite scroll thing
return false;
}
return (viewPortTop - distanceToViewportTop === 0);
}
});
nothing smart coming to my mind, but maybe it's that...
You've got the line:
if (meta.hasmore) {
in your getMore() function. Is this the case that you've got this meta field in one response and forgot in the other?

partial view loaded by Ajax do not render code after #RenderBody

I have an application developped in C# / MVC4.
It has a top menu and bottom menu.
A partial view is loaded in the main view when I click on a link (banana or apple) using ajax:
#Ajax.ActionLink("Connection", "Details", "SourceConfiguration", new { id = "4505F2DE-91A2-496B-9BCB-BD1D3C2C3FB1" }, new AjaxOptions { UpdateTargetId = "result" })
When the link is clicked, it should also modify the layout in order to display different top and bottom menus: (similar to Windows Azure bottom menu which display contextual action depending on where you are).
How I can I achieve that? (see below for what has been tested).
What has been tried so far:
The default _layout.cshtml contains
#RenderBody()
#RenderSection("Bottom", false)
the home/index.cshtml contains this code:
#section Bottom
{
the code to create the bottom menu
[...]
}
=> This is correctly rendered.
Here comes the problem:
each page in the views contain the Bottom section.
The bottom section is not displayed in pages called by partial view (ex: views/apple/index.cshtml).
What's the best way when I click on Apple to display the partial view and to display a specific top and bottom bar?
Got it:
in HomeController:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult MenuLayout(string name)
{
return PartialView("_MenuLayout", null);
}
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult MenuBottomLayout(string name)
{
return PartialView("_MenuBottomLayout", null);
}
In _Layout.cshtml
<div class="navcontainer">
</div>
<div class="">
#RenderBody()
</div>
<div class="navcontainerbottom">
</div>
And javascript code:
<script type="text/javascript">
var menuLoaded = false;
$(document).ready(function () {
if($('.navcontainer')[0].innerHTML.trim() == "")
{
$.ajax({
url: "#Url.Content("~/Home/MenuLayout")",
type: "GET",
success: function (response, status, xhr)
{
var nvContainer = $('.navcontainer');
nvContainer.html(response);
menuLoaded = true;
},
error: function (XMLHttpRequest, textStatus, errorThrown)
{
var nvContainer = $('.navcontainer');
nvContainer.html(errorThrown);
}
});
}
if($('.navcontainerbottom')[0].innerHTML.trim() == "")
{
$.ajax({
url: "#Url.Content("~/Home/MenuBottomLayout")",
type: "GET",
success: function (response, status, xhr)
{
var nvContainer = $('.navcontainerbottom');
nvContainer.html(response);
menuLoaded = true;
},
error: function (XMLHttpRequest, textStatus, errorThrown)
{
var nvContainer = $('.navcontainerbottom');
nvContainer.html(errorThrown);
}
});
}
});
</script>
And finally _MenuLayout.cshtml and MenuBottomLayout.cshtml contain the code that create the top and bottom menu.

Resources