Dailycode.info

Short solution for short problems

AngularJS: Back Button

Something simple, though not yet default in Angular + $stateprovider.

How to go to the previous state?

Lots of posts, easy solution. The best one yet is to save the previous state in the state itself when a state change was succesfull.

Just add these 3 lines to your app.run:

$rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState) {
	$state.previous = fromState;
});

Now the previous state is already saved and can be accessed anywhere the state is injected:

$scope.goBackToProject = function () {
	console.log('Back to: '+$state.previous);
	$state.go($state.previous);
}

And just call it onclick:

<button ng-click="goBackToProject()" class="btn btn-danger" type="button"><span class="glyphicon glyphicon-step-backward"></span> Back</button>

That's it!


AngularJS: UI router, subviews and passing parameters to controllers

I was struggling a while with AngularJS to have nested views and pass data between the controllers behind the views. The obvious and easy solution would be to set a variable in the rootscope and get in the other controller. That works fine until you are working with collections in collections.

My example looks like this:

 

The problem was that a Project had a collection of Zones. For the project, I created a view and a Controller. Now first I thought of using 1 view and 1 controller to show all the project with its zones and subzones. (btw each level can have pictures and properties).

 

1) It could not be accomplished simple with the current model, because the model was not loading its child objects. I could start building up the model in JavaScript and at the end bind it.

E.g. selectedProject.zones[0].subzones[0].pictures = getPictures()

But then I had to loop over all the child objects and get them from the server. I also had to rewrite a lot of code and could not reuse any view.

 

2) I could also enable the model on the server to load all its siblings, but that would be too easy. I wanted to solve it the hard way, only to learn more from AngularJS and its UI-Router.

If I loaded everything on the server, I also couldn’t reuse the current views, but still in my case it would have been the best solution.

 

3) Use the UI-router and nested views.

The challenge here was that I had to pass parameters to the nested controllers. When I loop over the Zones, I have to pass the zone_id to the ZoneController. To solve this, I ended up using the ng-init directive. This will init a variable in the scope of the controller before its loaded. So this is perfect!

<div class="panel panel-info">

    <div class="panel-heading">Zones</div>

    <div class="panel-body"ng-repeat="z in projectToPrint.zones">

        <div ui-view="zoneDetails@projectsfull"ng-init="zoneToPrint = z"></div>

    </div>

</div>

 

The StateProvider configuration it looks like this (For the moment only projects and zones, but the rest will use the same principle):

.state('projectsfull',{

    url:'/projectsfull',

    views:{

        '':{

            templateUrl:'/views/projects/project-full.html',

            controller:'projectsFullController',

        },

        'zoneDetails@projectsfull':

            {

                templateUrl:'/views/zones/zone-fulldetails.html',

                controller:'zonesFullController'

            },

        'pictureList@zoneDetails@projectsfull':{

            templateUrl:'/views/pictures/pictures-list.html'

        },

        'propertyList@zoneDetails@projectsfull':{

            templateUrl:'/views/properties/properties-list.html'

        }

    }

 

})

Now for every zone a $scope is created and the zoneToPrint is set to the child zone.

Using this I can get sub collections in my controller

if($scope.zoneToPrint !=null){

    if($scope.zoneToPrint.pic_id !=null){

        picturesService.getPictures($scope, $scope.zoneToPrint.pic_id, APIGeneralSettingsService);

    }

    else{

        $scope.pictures =null;

    }

    if($scope.zoneToPrint.prop_id !=null){

        propertiesService.getProperties($scope, $scope.zoneToPrint.prop_id, APIGeneralSettingsService);

    }

    else{

        $scope.properties =null;

    }

}

and bind them:

<div class="panel panel-info">

    <div class="panel-heading">Pictures</div>

    <div class="panel-body"ng-repeat="p in pictures">

        <div><b>ID:</b> {{ p.pic_id }}</div>

        <div><b>Seq:</b> {{ p.pic_seq }}</div>

        <div><b>Url:</b> {{ p.pic_onlineurl }}</div>

        <div><b>Date:</b> {{ p.pic_created|date:'yyyy-MM-dd' }}</div>

        <div href="#"class="thumbnail">

            <img class="img-responsive"ng-src="{{p.pic_onlineurl}}"

                 alt="{{p.pic_id }}">

        </div>

    </div>

</div>

 also I can bind this variable to the view:

<div class="panel panel-info">

    <div class="panel-body">

        <b>Id:</b> {{zoneToPrint.z_id}}

    </div>

    <div class="panel-body">

        <b>Titel:</b> {{zoneToPrint.z_title}}

    </div>

    <div class="panel-body">

        <b>Info:</b> {{zoneToPrint.z_info}}

    </div>

    <div class="panel-body">

        <b>Date:</b> {{zoneToPrint.z_date|date:'yyyy-MM-dd' }}

    </div>

    <div ui-view="propertyList@zoneDetails@projectsfull"></div>

    <div ui-view="pictureList@zoneDetails@projectsfull"></div>

</div>

Above you can also see that the pictures and properties are in a subview, but not controller defined, so just using the same scope!

 

 

The ng-init will happen before the controller is loaded, so the zoneToPrint is set for each zoneController. Based on this, the correct binding will happen. Works perfect.


JSON & EF: Error Self referencing loop detected for type System.data.entity occurs .

I got this error when I started to add the navigation properties to the entities. Because a master detail relation has got 2 kinds of navigation properties. The master gets the collection of childs and the child gets the master where it belongs to. JSON serialization will end up in a circular loop, since it serializes the child, then tries to serialize the parent, but this has a collection of child etc.

You can solve this many ways.

- If you do not need the parent navigation property, you can remove it. 

- You could set an attribute to the property: [JsonIgnore] [IgnoreDataMember]. The problem here is when you use the generated classes, the next time you generate it will be removed.

- Set lazy loading on your context to false: db.Configuration.LazyLoadingEnabled = false;

In my case I chose the first one, since the parent did not need to know about it's children.  


ios: Website not responsive on iphone

I'm making a back-end website that is Angular + Bootstrap. So this should work on practically all browsers. 

On my develop machine, the site works perfect, responsiveness is good, when I resize the browser, the site reacts. But on my iPhone the site always opened zoomed out. So too small to read. I was expecting it to react responsize.

This problem was solved by adding this meta tag:

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

Make sure also to clear the browsing history.



AngularJS: hide or show HTML elements

AngularJS makes it really easy ti hide or show elements.

In my case I wanted to show a button depending on whether there are child models available.

So just using the ng-show it works perfect!

<buttonng-click="goToZones()"class="btn btn-block btn-info"type="button"ng-show="showZones">Zones</button>

 <brng-show="showZones"/>

When the showZones is true, button, navigation and BR is shown:

 

So the button is hidden if showZones in the $scope is false and in the same time the BR element is hidden. 

The value is set when a project is selected:

$scope.$on('selectProject',function(event, data){

    $rootScope.selectedProject = data;

    if(data !=null){

        $rootScope.showZones = data.NrOfZones>0?true:false;

        $rootScope.showSubZones =false;

    }

    else{

        $rootScope.showZones =false;

        $rootScope.showSubZones =false;

    }

 

});


.Net: Ajax UpdatePanel causes DevExpress Controls to lose style after post

In my web application, I had a dev express gridview with a detail grid view. It was not so nice to see the form post backing after every click in the master grid, so I decided to use the ajax update panel.

The grid looks like this:

But after the first click the form looked like this:

The problem was apparently devexpress tries to edit the header of the page adding the style sheets links, so adding the runat="server" to your page header fixes this problem. In my case I had to add this to the master page and remove some <% tags in the header.

 <head runat="server">


iOS: Check if device is iPad or not

I have some screen that have different behaviour depending if its an iPad or not. Because iPad screen is a lot larger,  for iPhone I sometimes use a sub screen to lookup certain data, as for on the iPad I can keep it on screen. Not to easily check for iPad add these two lines to your class, or if used in different classes add it to your precompiled header file:

#define IDIOM    UI_USER_INTERFACE_IDIOM()

#define IPAD     UIUserInterfaceIdiomPad

Now you can check for iPad like this:

if (IDIOM == IPAD)

{

    iPad      

}

else

{

    iPhone

}


.Net WebAPI: add time zone suffix to datetime in JSON

On iOS, my JSON formatter needed to have the UTC format for date times. But My .Net WebAPI by default just formatted the date like this:

"timeStamp":"2015-01-04T00:00:00"

now just by adding these lines to the WebApiConfig.cs:

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;

json.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;

the date times got the correct format:

"timeStamp":"2015-01-04T00:00:00Z"


.Net WebAPI: A potentially dangerous Request.Path value was detected from the client (:).

Ever got this error?

A potentially dangerous Request.Path value was detected from the client (:).

I was trying to give a datetime in the url as parameter to a REST service. but when I used data time, the following error occurred.

http://localhost/Users/GetPlanForDate/2015-1-5%2008:00

First I changed the route, making the date a querystring.

http://localhost/Users/GetPlanForDate?date=2015-1-5%2008:00

This worked fine, but then I would have to change to many routes. So finally the solution came up.

I could just remove the ':' as potentially dangerous sign. The can be done in the web.config of your project:

Change this line:

<httpRuntime targetFramework="4.5" />

into this:

<httpRuntime targetFramework="4.5" requestPathInvalidCharacters="&lt;,&gt;,*,%,&amp;,\,?" />

Now the time using the ':' will be passed to your web api.

Some functions have the datetime as first parameter, but have more following, like this:

http://localhost/Users/GetPlanForDate/2015-1-5%2008:00/1

So in this case it's nice that you can use the Route parameters for datetime.

[Route("Users/GetPlanForDate/{date}/{shift}")]

public GalvaSFIMobileDataLayer.GP_MES_ShiftPlans GetPlanForDate(DateTime date, int shift)

{

            //GetMESHeaders(OperationContext.Current);

            return PL.GetPlanForDate(date, shift);

}


AngularJS - WebAPI: No 'Access-Control-Allow-Origin'

Got this error: XMLHttpRequest cannot load http://localhost:777/api/products/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:777' is therefore not allowed access. The response had HTTP status code 405.

It was not so easy to sfind out what the problem was, but then it had something to do with enabling cross origin requests. When you are developing WebAPI back end that is not on the same uri as the front end angular JS site, it could be that you have this error. I even got it on my local host, using different ports for the 2 sites. Simple solution, which will help to secure the WebAPI.

You will first have to allow the cros origin requests in your WebApiconfig.cs:

config.EnableCors();

If VS gives problems, then use the nuget package manager to add this


Then first add this code to the WebApiConfig:

config.EnableCors();

And then you will have to allow ip to connect to your webapi in your controllers like this:

// GET: api/Products/Mark  
[EnableCors("http://localhost:778","*","*")] 
public List<Product> GetProduct()
You can also allow all methods in your API by putting the EnableCors attribute above the class:

using System.Web.Http.Cors;

namespace MyProject.Controllers

{

    [EnableCors("http://localhost:778", "*", "*")]

    public class UsersController : ApiController