HTML website url contains /#[object Object] when navigating - html

I have a website and it contains the following code:
<li class="scroll-to-section">Services</li>
and the appropriate section:
<section class="section" id="services">
...
</section>
When I press the li element, the page scrolls to the services section as expected however, the url is appended with /#[object Object] instead of /services.
Here's an image:
Any idea about what the issue may be?
EDIT: Sorry, forgot to add the javascript: The issue was the new_target variable. I had to change it to new_target as it was also target before and that fixed the issue!
$(document).ready(function() {
$(document).on("scroll", onScroll);
//smoothscroll
$('a[href^="#"]').on("click", function(e) {
e.preventDefault();
$(document).off("scroll");
$("a").each(function() {
$(this).removeClass("active");
});
$(this).addClass("active");
var target = this.hash,
menu = target;
var new_target = $(this.hash);
$("html, body")
.stop()
.animate(
{
scrollTop: new_target.offset().top - 79
},
500,
"swing",
function() {
window.location.hash = target;
$(document).on("scroll", onScroll);
}
);
});
});

The question doesn't allows us to examine the problem in big detail but here is -at a glance- what is going on:
You are trying to assign an object to a place where only strings are valid.
Take a look at the following example:
function changeText() {
document.getElementById("input").value = "hello"
}
function changeTextWrong() {
document.getElementById("input").value = {link: "hello"}
}
<input id="input" value="sample text"/>
<button onclick="changeText()">change text (OK)</button>
<button onclick="changeTextWrong()">change text (WRONG)</button>
When the input text (equivalent to the url bar) receives the text "hello" it works because "hello" is a text. However when the input text receives an object, this object is then converted into a string. Any object converted into a string is equivalent to "[object Object]".
Solution? Instead of doing window.location.hash = object you very likely need to do something like window.location.hash = object.hash, or window.location.hash = object.WhAtEvEr depending on the object's actual content.

i think you tried to simplify the question without presenting us the complete or relevant code.
From your example, if you only do that it should work but i have a feeling that your code is doing more than that.
#adelriosantiago was right in pointing out that you might return an object instead of the expected string.

Related

Remove child element's attribute from Polymer js

I've a custom element which, among other things, has a core-input and a paper button in it.
When the element is created, the input is disabled, and I want to enable it when I tap the button.
I've tried several ways and can't access the input's attribute.
<paper-input-decorator label="Nombre de usuario" floatingLabel>
<input id="usernameinput" value="{{UserName}}" is="core-input" disabled />
</paper-input-decorator>
<paper-button raised id="edprobutton" on-tap="{{edbutTapped}}">EDITAR</paper-button>
What should I write in
edbutTapped: function () {
},
EDIT
So, I've learned that the problem was that my username input element was inside a repeat template, and that's bad for what I was trying to do. Now I'm trying to bind a single json object to my element, with no luck so far.
What I have right now:
In my Index page:
<profile-page id="profpage" isProfile="true" entity="{{profEntity}}"></profile-page>
<script>
$(document).ready(function () {
var maintemplate = document.querySelector('#fulltemplate');
$.getJSON('api/userProfile.json', function (data) {
var jsonString = JSON.stringify(data);
alert(jsonString);
maintemplate.profEntity = jsonString;
});
}
</script>
In my element's page:
<polymer-element name="profile-page" attributes="isprofile entity">
<template>
<style>
[...]
</style>
<div flex vertical layout>
<core-label class="namepro">{{entity.Name}}</core-label>
<core-label class="subpro">{{entity.CompanyPosition}}</core-label>
<core-label class="subpro">{{entity.OrgUnitName}}</core-label>
</div>
</template>
</polymer-element>
And my JSON looks like this:
{"Name": "Sara Alvarez","CompanyPosition": "Desarrollo","OrgUnitName": "N-Adviser"}
I'm asuming I need to "update" my element somehow after changing its entity attribute?
Try the following
<script>
Polymer({
edbutTapped: function () {
this.$.usernameinput.disabled = false;
}
});
</script>
The this.$ allows you to access controls defined in an elements and the usernameinput is the id you assigned to the input.
This can go below the closing tag of the element you are defining.
'disabled' is conditional-attribute.
So this will be the correct use of it:
<input id="usernameinput" value="{{UserName}}" is="core-input" disabled?="{{isDisabled}}" />
In the prototype:
//first disable the field, can be done in ready callback:
ready: function () {
this.isDisabled = 'true';
}
//set idDisabled to 'false' i.e. enable the input
edbutTapped: function () {
this.isDisabled = 'false';
},
OK this is going to be a long answer (hence why I am not entering this as an edit of my original answer). I've just done something which is functionally the same.
The first thing is this code;
$.getJSON('api/userProfile.json', function (data) {
var jsonString = JSON.stringify(data);
alert(jsonString);
maintemplate.profEntity = jsonString;
});
Polymer has a control called core-ajax - this as it's name suggests makes an ajax call. The other really nice thing is that it can be made to execute when the URL changes. This is the code from the project I've got.
<core-ajax id="ajax"
auto=true
method="POST"
url="/RoutingMapHandler.php?Command=retrieve&Id=all"
response="{{response}}"
handleas="json"
on-core-error="{{handleError}}"
on-core-response="{{handleResponse}}">
</core-ajax>
The auto is the bit which tells it to fire when the URL changes. The description of auto from the polymer documentation is as follows;
With auto set to true, the element performs a request whenever its
url, params or body properties are changed.
you don't need the on-core-response but the on-core-error might be more useful. For my code response contains the JSON returned.
So for your code - it would be something like this
<core-ajax id="ajax"
auto=true
method="POST"
url="/api/userProfile.json"
response="{{jsonString}}"
handleas="json"
on-core-error="{{handleError}}" >
</core-ajax>
Now we have the data coming into your project we need to handle this. This is done by making use of Polymer's data-binding.
Lets detour to the element you are creating. Cannot see anything wrong with the following line.
<polymer-element name="profile-page" attributes="isprofile entity">
We have an element called 'profile-page' with two properties 'isprofile' and 'entity'.
Only because my Javascript leaves a bit to be desired I would pass each property as a seperate entity making that line
<polymer-element name="profile-page" attributes="isprofile name companyposition OrgUnitName">
Then at the bottom of your element define a script tag
<script>
Polymer({
name: "",
companyposition: "",
OrgUnitName: ""
});
</script>
Now back to the calling (profile-page). The following code (from my project) has the following;
<template repeat="{{m in response.data}}">
<map-list-element mapname="{{m.mapName}}" recordid="{{m.Id}}" on-show-settings="{{showSettings}}">
</map-list-element>
</template>
Here we repeat the following each element. In your case you only have one entry and it is stored in jsonString so your template is something like this
<template repeat="{{u in jsonString}}">
<profile-page name="{{u.name}} companyposition="{{u.companyposition}}" OrgUnitName="{{u.OrgUnitName}}">
</profile-page>
</template>
Now we get to the issue you have. Return to your profie-page element. Nothing wrong with the line
on-tap="{{edbutTapped}}"
This calls a function called edbutTapped. Taking the code I gave you earlier
<script>
Polymer({
edbutTapped: function () {
this.$.usernameinput.disabled = false;
}
});
</script>
The only thing to change here is add the following code
created: function() {
this.$.usernameinput.disabled = true;
},
This is inserted after the Polymer({ line. I cannot see in your revised code where the usernameinput is defined but I am assuming you have not posted it and it is defined in the element.
And you should be working, but remember to keep your case consistent and to be honest I've not been - certain parts of Polymer are case sensitive - that catches me out all the time :)

HTML form validation with Google Apps Script's HTML Service

I'm trying to use HTML form validation when using Google Apps Script's HTML Service. As another user asked, according to the documentation example, you must use a button input instead of a submit input. Using a submit button seems to do the validation, but the server function is called anyway. The answer given to that user didn't work for me. Also, I want to call two functions when submitting the form and this can make it more complex.
This is what I'm trying to do: The user fills a form and I generate a Google Doc and give him the URL. When he clicks the submit button, I show him a jQuery UI dialog saying "Your document is being created" with a nice spinner. Then, when the document is generated, I give him the link. I use the success handler to show the result when the Google Doc stuff is finished, but meanwhile I need a function to show the spinner. I don't know if there is a better way to do that than adding another function to the onclick event and maybe it can be damaging the process in some way. Is there a way not to call any of these functions if the form is not valid (using HTML validation)?
This is a simplified version of my code:
Code.gs
function generateDocument(formObject) {
var doc = DocumentApp.create("Document name");
...
return doc.getUrl();
}
Page.html
<main>
<form id="myForm">
...
<input type="button" value="Generate document"
onclick="showProgress();
google.script.run
.withSuccessHandler(openDocument)
.generateDocument(this.parentNode);"/>
</form>
<div id="dialog-confirm" title="Your document">
<div id="dialog-confirm-text"></div>
</div>
Javascript.html
$( "#dialog-confirm" ).dialog({ autoOpen: false, resizable: false, modal: true });
function showProgress() {
$( "#dialog-confirm" ).dialog({ buttons: [ { text: "Cancel", click: function() { $( this ).dialog( "close" ); } } ] });
$( "#dialog-confirm" ).dialog( "open" );
$( "#dialog-confirm-text" ).html( "<br />Wait a second, your document is being generated...<br /><br /><img src='http://i.stack.imgur.com/FhHRx.gif' alt='Spinner'></img>" );
return false;
}
function openDocument(url) {
$( "#dialog-confirm" ).dialog({ autoOpen: false, resizable: false, width: 400, buttons: [ { text: "Ok", click: function() { $( this ).dialog( "close" ); } } ] });
$( "#dialog-confirm-text" ).html( '<br />Click here to open and print your document!' );
return false;
}
All three HTML docs are joined together (and working with its respective tags) with the include function as recommended in the documentation.
The Cancel button in the dialog will close it but won't stop the doc being created. Is it possible to stop this process?
Here's a solution that I found:
"<input type='submit' onclick='if(verifyForm(this.parentNode)===true){google.script.run.withSuccessHandler(YOUROUTPUT).YOURFUNCTION(this.parentNode); return false;}' value='Submit'></form>";
JavaScript side
function verifyForm(){
var elements = document.getElementById("myForm").elements;
for (var i = 0, element; element = elements[i++];) {
if (element.hasAttribute("required") && element.value === ""){
resetInputs();
return false;
}
if (element.hasAttribute("pattern")){
var value = element.value;
if(value.match(element.pattern)){
}else{
resetInputs();
return false;
}
}
}
return true;
}
Calling the window has issues in iOS sometimes, which is why I investigated this further.
Move the function call to the <form> element; remove any function call from the submit input element; and put intermediary JavaScript code into a <script> tag:
<input tabindex="9" type="submit" value="Save Input" id='idInputBtn'>
<form id="myInputForm" name="input" onsubmit="fncWriteInput(this)">
<script>
window.fncWriteInput= function(argTheInfo) {
// Do additional checks here if you want
var everythingIsOk = . . . . . . . ;
if (everythingIsOk) {
google.script.run
.withSuccessHandler(openDocument)
.generateDocument(argTheInfo);
};
};
Notice that this.parentNode gets removed to the arg of the function call, and just use this in the function argument because the function is getting called from the <form> element, which is the parent.
If there are any errors, the form will not be submitted, and the user will get a msg that something was wrong. No code will run.
This is pseudo code, but I do use a set up like this in my application. But use developer tools and you can put a break point right in your browser and step through every line to test it without needing to put in console.log statements.

Compiling dynamic HTML strings from database

The Situation
Nested within our Angular app is a directive called Page, backed by a controller, which contains a div with an ng-bind-html-unsafe attribute. This is assigned to a $scope var called 'pageContent'. This var gets assigned dynamically generated HTML from a database. When the user flips to the next page, a called to the DB is made, and the pageContent var is set to this new HTML, which gets rendered onscreen through ng-bind-html-unsafe. Here's the code:
Page directive
angular.module('myApp.directives')
.directive('myPage', function ($compile) {
return {
templateUrl: 'page.html',
restrict: 'E',
compile: function compile(element, attrs, transclude) {
// does nothing currently
return {
pre: function preLink(scope, element, attrs, controller) {
// does nothing currently
},
post: function postLink(scope, element, attrs, controller) {
// does nothing currently
}
}
}
};
});
Page directive's template ("page.html" from the templateUrl property above)
<div ng-controller="PageCtrl" >
...
<!-- dynamic page content written into the div below -->
<div ng-bind-html-unsafe="pageContent" >
...
</div>
Page controller
angular.module('myApp')
.controller('PageCtrl', function ($scope) {
$scope.pageContent = '';
$scope.$on( "receivedPageContent", function(event, args) {
console.log( 'new page content received after DB call' );
$scope.pageContent = args.htmlStrFromDB;
});
});
That works. We see the page's HTML from the DB rendered nicely in the browser. When the user flips to the next page, we see the next page's content, and so on. So far so good.
The Problem
The problem here is that we want to have interactive content inside of a page's content. For instance, the HTML may contain a thumbnail image where, when the user clicks on it, Angular should do something awesome, such as displaying a pop-up modal window. I've placed Angular method calls (ng-click) in the HTML strings in our database, but of course Angular isn't going to recognize either method calls or directives unless it somehow parses the HTML string, recognizes them and compiles them.
In our DB
Content for Page 1:
<p>Here's a cool pic of a lion. <img src="lion.png" ng-click="doSomethingAwesone('lion', 'showImage')" > Click on him to see a large image.</p>
Content for Page 2:
<p>Here's a snake. <img src="snake.png" ng-click="doSomethingAwesone('snake', 'playSound')" >Click to make him hiss.</p>
Back in the Page controller, we then add the corresponding $scope function:
Page controller
$scope.doSomethingAwesome = function( id, action ) {
console.log( "Going to do " + action + " with "+ id );
}
I can't figure out how to call that 'doSomethingAwesome' method from within the HTML string from the DB. I realize Angular has to parse the HTML string somehow, but how? I've read vague mumblings about the $compile service, and copied and pasted some examples, but nothing works. Also, most examples show dynamic content only getting set during the linking phase of the directive. We would want Page to stay alive throughout the life of the app. It constantly receives, compiles and displays new content as the user flips through pages.
In an abstract sense, I guess you could say we are trying to dynamically nest chunks of Angular within an Angular app, and need to be able to swap them in and out.
I've read various bits of Angular documentation multiple times, as well as all sorts of blog posts, and JS Fiddled with people's code. I don't know whether I'm completely misunderstanding Angular, or just missing something simple, or maybe I'm slow. In any case, I could use some advice.
ng-bind-html-unsafe only renders the content as HTML. It doesn't bind Angular scope to the resulted DOM. You have to use $compile service for that purpose. I created this plunker to demonstrate how to use $compile to create a directive rendering dynamic HTML entered by users and binding to the controller's scope. The source is posted below.
demo.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="angular.js#1.0.7" data-semver="1.0.7" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js"></script>
<script src="script.js"></script>
</head>
<body>
<h1>Compile dynamic HTML</h1>
<div ng-controller="MyController">
<textarea ng-model="html"></textarea>
<div dynamic="html"></div>
</div>
</body>
</html>
script.js
var app = angular.module('app', []);
app.directive('dynamic', function ($compile) {
return {
restrict: 'A',
replace: true,
link: function (scope, ele, attrs) {
scope.$watch(attrs.dynamic, function(html) {
ele.html(html);
$compile(ele.contents())(scope);
});
}
};
});
function MyController($scope) {
$scope.click = function(arg) {
alert('Clicked ' + arg);
}
$scope.html = '<a ng-click="click(1)" href="#">Click me</a>';
}
In angular 1.2.10 the line scope.$watch(attrs.dynamic, function(html) { was returning an invalid character error because it was trying to watch the value of attrs.dynamic which was html text.
I fixed that by fetching the attribute from the scope property
scope: { dynamic: '=dynamic'},
My example
angular.module('app')
.directive('dynamic', function ($compile) {
return {
restrict: 'A',
replace: true,
scope: { dynamic: '=dynamic'},
link: function postLink(scope, element, attrs) {
scope.$watch( 'dynamic' , function(html){
element.html(html);
$compile(element.contents())(scope);
});
}
};
});
Found in a google discussion group. Works for me.
var $injector = angular.injector(['ng', 'myApp']);
$injector.invoke(function($rootScope, $compile) {
$compile(element)($rootScope);
});
You can use
ng-bind-html https://docs.angularjs.org/api/ng/service/$sce
directive to bind html dynamically.
However you have to get the data via $sce service.
Please see the live demo at http://plnkr.co/edit/k4s3Bx
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope,$sce) {
$scope.getHtml=function(){
return $sce.trustAsHtml("<b>Hi Rupesh hi <u>dfdfdfdf</u>!</b>sdafsdfsdf<button>dfdfasdf</button>");
}
});
<body ng-controller="MainCtrl">
<span ng-bind-html="getHtml()"></span>
</body>
Try this below code for binding html through attr
.directive('dynamic', function ($compile) {
return {
restrict: 'A',
replace: true,
scope: { dynamic: '=dynamic'},
link: function postLink(scope, element, attrs) {
scope.$watch( 'attrs.dynamic' , function(html){
element.html(scope.dynamic);
$compile(element.contents())(scope);
});
}
};
});
Try this element.html(scope.dynamic);
than element.html(attr.dynamic);

How to dynamic add new element in Angularjs

I have a ng-repeat to loop my object value to view.
Then I want to have a button to add new blank element to the last of ng-repeat value.
How can I do this in angular?
My data is json object. I tried
In controller
$scope.objs = {'a': 'a', 'b':'b'};
In view
{{Object.keys(objs).length}};
But nothing show in view.
Update
<div ng-repeat="docstep in docs.docsteps" class="docstep">
{{docstep.text}}
</div>
Then I want to get the length of objects so I can .length + 1 in the button click
But I have no idea how to get objects length. Or is there any better idea?
Bind a click handler to the button using ng-click:
<div ng-repeat="docstep in docs.docsteps" class="docstep">
<input type="text" value="{{docstep.text}}">
</div>
<button ng-click="addNew()">Add another input</button>
When this button is clicked. It will add another blank input
<br>Which the new input will be docstep3
This is how your JS should look:
var myApp = angular.module('myApp',[]);
myApp.run(function($rootScope){
$rootScope.docs = {
"docsteps" : {
"docstep1" : {
"text" : "a"
},
"docstep2" : {
"text" : "b"
}
}
}
var c = 2;
$rootScope.addNew = function(){
count++;
$rootScope.docs.docsteps["docstep"+count] = {"text":count}
}
});
NOTE: You should use ng-app to define work area for angular and use controllers to reside the models(docs) and define the behaviour of your view (addNew).
I took your ng-repeat and made it work. Notice I put your object in the $rootScope but you can apply the same object to any scope that your ng-repeat is in.
JS
var myApp = angular.module('myApp',[]);
myApp.run(function($rootScope){
$rootScope.docs={docsteps:[{text:'A'},{text:'B'},{text:'C'}]};
});
JSFIDDLE: http://jsfiddle.net/mac1175/Snn9p/

How do I trigger a function to execute after external HTML is loaded?

JS:
$(document).ready(function(){
$("#loader").load("external.html");
$("#buttonClickText").live('click', function() {
$("#buttonClickText").text("Text changed after button click.");
});
// MYSTERY FUNCTION
$("#pageLoadText").text("Text changed after external HTML was loaded.");
//
});
External HTML:
<div id="buttonClickText">
This text changes when clicked.
</div>
<div id="pageLoadText">
This text should have changed when external HTML was loaded, but didn't.
</div>
Main HTML (just showing the relevant tag):
<div id="loader"></div>
Also, I know .live() is deprecated for jQuery 1.7+, I'm guessing the solution will be similar using .on()
Thanks!
from http://api.jquery.com/load/:
This method is the simplest way to fetch data from the server. It is
roughly equivalent to $.get(url, data, success) except that it is a
method rather than global function and it has an implicit callback
function. When a successful response is detected (i.e. when textStatus
is "success" or "notmodified"), .load() sets the HTML contents of the
matched element to the returned data.
Just pass a function as the second argument.
$('#result').load('ajax/test.html', function() {
alert('Load was performed.');
});
below is the solution for the issue:
$(document).ready(function(){
$("#loader").load("external.html", function()
{
$("#pageLoadText").text("Text changed after external HTML was loaded.");
}
);
$("#buttonClickText").live('click', function() {
$("#buttonClickText").text("Text changed after button click.");
});
});